Railway Operation Simulator  v2.8.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
241 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
242 {
243  if(lower.second < higher.second)
244  {
245  return(true);
246  }
247  else if(lower.second > higher.second)
248  {
249  return(false);
250  }
251  else if(lower.second == higher.second)
252  {
253  if(lower.first < higher.first)
254  {
255  return(true);
256  }
257  }
258  return(false);
259 }
260 
261 // ---------------------------------------------------------------------------
262 // PrefDirElement Functions
263 // ---------------------------------------------------------------------------
264 
265 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
266  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
267  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
268 {
269  if(!EntryExitNumber())
270  {
271  throw Exception("EXNumber failure in TPrefDirElement constructor");
272  }
275 }
276 
277 // ---------------------------------------------------------------------------
278 
279 AnsiString TPrefDirElement::LogPrefDir() const
280 // for debugging when passed as a call parameter
281 {
282  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
283  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
284  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
285  AnsiString(TrainIDOnBridgeTrackPos23);
286 
287 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
288  return(LogString);
289 }
290 
291 // ---------------------------------------------------------------------------
292 
293 bool TPrefDirElement::EntryExitNumber() // true for valid number
294 /*
295  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
296  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
297  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
298  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
299  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
300  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
301  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
302  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
303  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
304 */
305 
306 {
307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
308  int EXArray[16][2] =
309  {{4, 6}, {2, 8}, // horizontal & vertical
310  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
311  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
312  {1, 9}, {3, 7}}; // forward & reverse diagonals
313 
314  int EXNum = -1;
315  int Entry, Exit;
316 
317  if(ELink > -1)
318  {
319  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
320  }
321  else if(Link[2] == -1)
322  {
323  Entry = Link[0];
324  }
325  else
326  {
327  Utilities->CallLogPop(122);
328  return(false);
329  }
330  if(XLink > -1)
331  {
332  Exit = XLink;
333  }
334  else if(Link[2] == -1)
335  {
336  Exit = Link[1];
337  }
338  else
339  {
340  Utilities->CallLogPop(123);
341  return(false);
342  }
343  for(int x = 0; x < 16; x++)
344  {
345  if((Entry == EXArray[x][0]) && (Exit == EXArray[x][1]) || (Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))
346  {
347  EXNum = x;
348  }
349  }
350  if(EXNum == -1)
351  {
352  Utilities->CallLogPop(124);
353  return(false);
354  }
355  int BrNum = -1;
356 
357 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
358  the graphic for each of which is different because of the shape of the overbridge. The basic
359  entry/exit value is computed above, and this used to select only from elements with that entry/exit
360  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
361  int BrEXArray[24][2] = {
362  {4,6},{2,8},{1,9},{3,7},
363  {1,9},{3,7},{1,9},{3,7},
364  {2,8},{4,6},{2,8},{4,6}
365 */
366 
367  if(TrackType == Bridge)
368  {
369  if(EXNum == 1)
370  {
371  if(SpeedTag == 49)
372  {
373  BrNum = 1 + 16;
374  }
375  else if(SpeedTag == 54)
376  {
377  BrNum = 8 + 16;
378  }
379  else if(SpeedTag == 55)
380  {
381  BrNum = 10 + 16;
382  }
383  }
384  else if(EXNum == 0)
385  {
386  if(SpeedTag == 48)
387  {
388  BrNum = 0 + 16;
389  }
390  else if(SpeedTag == 58)
391  {
392  BrNum = 11 + 16;
393  }
394  else if(SpeedTag == 59)
395  {
396  BrNum = 9 + 16;
397  }
398  }
399  else if(EXNum == 14)
400  {
401  if(SpeedTag == 50)
402  {
403  BrNum = 2 + 16;
404  }
405  else if(SpeedTag == 52)
406  {
407  BrNum = 4 + 16;
408  }
409  else if(SpeedTag == 57)
410  {
411  BrNum = 6 + 16;
412  }
413  }
414  else if(EXNum == 15)
415  {
416  if(SpeedTag == 51)
417  {
418  BrNum = 3 + 16;
419  }
420  else if(SpeedTag == 53)
421  {
422  BrNum = 7 + 16;
423  }
424  else if(SpeedTag == 56)
425  {
426  BrNum = 5 + 16;
427  }
428  }
429  }
430  if(BrNum == -1)
431  {
432  EXNumber = EXNum;
433  }
434  else
435  {
436  EXNumber = BrNum;
437  }
438  Utilities->CallLogPop(125);
439  return(true);
440 }
441 
442 // ---------------------------------------------------------------------------
443 
445 /*
446  This is the basic track graphic for use in plotting the original graphic during route flashing.
447  Enter with all set apart from EXGraphic & EntryDirectionGraphic
448 */
449 {
450  if(SpeedTag == 64)
451  {
452  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
453 
454  }
455  if(SpeedTag == 65)
456  {
457  return(RailGraphics->LinkGraphicsPtr[17]);
458  }
459  if(SpeedTag == 66)
460  {
461  return(RailGraphics->LinkGraphicsPtr[18]);
462  }
463  if(SpeedTag == 67)
464  {
465  return(RailGraphics->LinkGraphicsPtr[19]);
466  }
467  if(SpeedTag == 80)
468  {
469  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
470 
471  }
472  if(SpeedTag == 81)
473  {
474  return(RailGraphics->LinkGraphicsPtr[21]);
475  }
476  if(SpeedTag == 82)
477  {
478  return(RailGraphics->LinkGraphicsPtr[22]);
479  }
480  if(SpeedTag == 83)
481  {
482  return(RailGraphics->LinkGraphicsPtr[23]);
483  }
484  if(SpeedTag == 84)
485  {
486  return(RailGraphics->LinkGraphicsPtr[24]);
487  }
488  if(SpeedTag == 85)
489  {
490  return(RailGraphics->LinkGraphicsPtr[25]);
491  }
492  if(SpeedTag == 86)
493  {
494  return(RailGraphics->LinkGraphicsPtr[26]);
495  }
496  if(SpeedTag == 87)
497  {
498  return(RailGraphics->LinkGraphicsPtr[27]);
499  }
500  if(SpeedTag == 129)
501  {
502  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
503 
504  }
505  if(SpeedTag == 130)
506  {
507  return(RailGraphics->LinkGraphicsPtr[29]);
508  }
509  if(XLinkPos == -1) // not set, could be first element or last element = leading point
510  {
511 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
512 // Points & don't want to display these)
513  if(Link[2] != -1)
514  {
515  return(0); // i.e. complex element, don't display
516  }
517  else
518  {
519  if(!EntryExitNumber())
520  {
521  throw Exception("Error in EntryExitNumber 4");
522  }
523  else
524  {
526  }
527  }
528  }
529  if(EXNumber > 15) // underbridge
530  {
531  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
532  }
533  else
534  {
536  }
537 }
538 
539 // ---------------------------------------------------------------------------
540 
542 /*
543  As above but for PrefDir graphics.
544 */
545 {
546  if(SpeedTag == 64)
547  {
548  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
549 
550  }
551  if(SpeedTag == 65)
552  {
554  }
555  if(SpeedTag == 66)
556  {
558  }
559  if(SpeedTag == 67)
560  {
562  }
563  if(SpeedTag == 80)
564  {
565  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
566 
567  }
568  if(SpeedTag == 81)
569  {
571  }
572  if(SpeedTag == 82)
573  {
575  }
576  if(SpeedTag == 83)
577  {
579  }
580  if(SpeedTag == 84)
581  {
583  }
584  if(SpeedTag == 85)
585  {
587  }
588  if(SpeedTag == 86)
589  {
591  }
592  if(SpeedTag == 87)
593  {
595  }
596  if(SpeedTag == 129)
597  {
598  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
599 
600  }
601  if(SpeedTag == 130)
602  {
604  }
605  if(XLinkPos == -1) // not set, could be first element or last element = leading point
606  {
607 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
608  if(Link[2] != -1)
609  {
610  return(0); // i.e. complex element, don't display
611  }
612  else
613  {
614  if(!EntryExitNumber())
615  {
616  throw Exception("Error in EntryExitNumber 5");
617  }
618  else
619  {
621  }
622  }
623  }
624  if(EXNumber > 15) // underbridge
625  {
627  }
628  else
629  {
631  }
632 }
633 
634 // ---------------------------------------------------------------------------
635 
636 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
637 /*
638  As above but for route graphics.
639 */
640 {
641  if(!AutoSigsFlag && !PrefDirRoute)
642  {
643  if(SpeedTag == 64)
644  {
645  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
646 
647  }
648  if(SpeedTag == 65)
649  {
651  }
652  if(SpeedTag == 66)
653  {
655  }
656  if(SpeedTag == 67)
657  {
659  }
660  if(SpeedTag == 80)
661  {
662  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
663 
664  }
665  if(SpeedTag == 81)
666  {
668  }
669  if(SpeedTag == 82)
670  {
672  }
673  if(SpeedTag == 83)
674  {
676  }
677  if(SpeedTag == 84)
678  {
680  }
681  if(SpeedTag == 85)
682  {
684  }
685  if(SpeedTag == 86)
686  {
688  }
689  if(SpeedTag == 87)
690  {
692  }
693  if(SpeedTag == 129)
694  {
695  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
696 
697  }
698  if(SpeedTag == 130)
699  {
701  }
702  if(XLinkPos == -1) // not set, could be first element or last element = leading point
703  {
704  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
705  if(Link[2] != -1)
706  {
707  return(0); // i.e. complex element, don't display
708  }
709  else
710  {
711  if(!EntryExitNumber())
712  {
713  throw Exception("Error in EntryExitNumber 6");
714  }
715  else
716  {
718  }
719  }
720  }
721  if(EXNumber > 15) // underbridge
722  {
724  }
725  else
726  {
728  }
729  }
730 
731  else if(!AutoSigsFlag && PrefDirRoute)
732  {
733  if(SpeedTag == 64)
734  {
735  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
736 
737  }
738  if(SpeedTag == 65)
739  {
741  }
742  if(SpeedTag == 66)
743  {
745  }
746  if(SpeedTag == 67)
747  {
749  }
750  if(SpeedTag == 80)
751  {
752  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
753 
754  }
755  if(SpeedTag == 81)
756  {
758  }
759  if(SpeedTag == 82)
760  {
762  }
763  if(SpeedTag == 83)
764  {
766  }
767  if(SpeedTag == 84)
768  {
770  }
771  if(SpeedTag == 85)
772  {
774  }
775  if(SpeedTag == 86)
776  {
778  }
779  if(SpeedTag == 87)
780  {
782  }
783  if(SpeedTag == 129)
784  {
785  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
786 
787  }
788  if(SpeedTag == 130)
789  {
791  }
792  if(XLinkPos == -1) // not set, could be first element or last element = leading point
793  {
794  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
795  if(Link[2] != -1)
796  {
797  return(0); // i.e. complex element, don't display
798  }
799  else
800  {
801  if(!EntryExitNumber())
802  {
803  throw Exception("Error in EntryExitNumber 10");
804  }
805  else
806  {
808  }
809  }
810  }
811  if(EXNumber > 15) // underbridge
812  {
814  }
815  else
816  {
818  }
819  }
820 
821  else
822  {
823  if(SpeedTag == 64)
824  {
825  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
826 
827  }
828  if(SpeedTag == 65)
829  {
831  }
832  if(SpeedTag == 66)
833  {
835  }
836  if(SpeedTag == 67)
837  {
839  }
840  if(SpeedTag == 80)
841  {
842  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
843 
844  }
845  if(SpeedTag == 81)
846  {
848  }
849  if(SpeedTag == 82)
850  {
852  }
853  if(SpeedTag == 83)
854  {
856  }
857  if(SpeedTag == 84)
858  {
860  }
861  if(SpeedTag == 85)
862  {
864  }
865  if(SpeedTag == 86)
866  {
868  }
869  if(SpeedTag == 87)
870  {
872  }
873  if(SpeedTag == 129)
874  {
875  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
876 
877  }
878  if(SpeedTag == 130)
879  {
881  }
882  if(XLinkPos == -1) // not set, could be first element or last element = leading point
883  {
884  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
885  if(Link[2] != -1)
886  {
887  return(0); // i.e. complex element, don't display
888  }
889  else
890  {
891  if(!EntryExitNumber())
892  {
893  throw Exception("Error in EntryExitNumber 11");
894  }
895  else
896  {
898  }
899  }
900  }
901  if(EXNumber > 15) // underbridge
902  {
904  }
905  else
906  {
908  }
909  }
910 }
911 
912 // ---------------------------------------------------------------------------
913 
915 /*
916  As above but for route flashing graphics. (Disused - now combined with above)
917 */
918 {
919  if(SpeedTag == 64)
920  {
921  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
922 
923  }
924  if(SpeedTag == 65)
925  {
927  }
928  if(SpeedTag == 66)
929  {
931  }
932  if(SpeedTag == 67)
933  {
935  }
936  if(SpeedTag == 80)
937  {
938  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
939 
940  }
941  if(SpeedTag == 81)
942  {
944  }
945  if(SpeedTag == 82)
946  {
948  }
949  if(SpeedTag == 83)
950  {
952  }
953  if(SpeedTag == 84)
954  {
956  }
957  if(SpeedTag == 85)
958  {
960  }
961  if(SpeedTag == 86)
962  {
964  }
965  if(SpeedTag == 87)
966  {
968  }
969  if(SpeedTag == 129)
970  {
971  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
972 
973  }
974  if(SpeedTag == 130)
975  {
977  }
978  if(XLinkPos == -1) // not set, could be first element or last element = leading point
979  {
980 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
981  if(Link[2] != -1)
982  {
983  return(0); // i.e. complex element, don't display
984  }
985  else
986  {
987  if(!EntryExitNumber())
988  {
989  throw Exception("Error in EntryExitNumber 7");
990  }
991  else
992  {
994  }
995  }
996  }
997  if(EXNumber > 15) // underbridge
998  {
1000  }
1001  else
1002  {
1004  }
1005 }
1006 
1007 // ---------------------------------------------------------------------------
1008 
1010 /*
1011  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1012 */
1013 {
1014  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1015  {
1017  }
1018  else
1019  {
1020  throw Exception("Error in EntryExitNumber 8");
1021  }
1022 }
1023 
1024 // ---------------------------------------------------------------------------
1025 
1026 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1027 /*
1028  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1029 */
1030 {
1031  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1032  {
1033  if(!AutoSigsFlag && !PrefDirRoute)
1034  {
1036  }
1037  else if(!AutoSigsFlag && PrefDirRoute)
1038  {
1040  }
1041  else
1042  {
1044  }
1045  }
1046  else
1047  {
1048  throw Exception("Error in EntryExitNumber 9");
1049  }
1050 }
1051 
1052 // ---------------------------------------------------------------------------
1053 
1055 /*
1056  Set == operator when TrackVectorPosition, ELink & XLink all same
1057 */
1058 {
1059  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1060  {
1061  return(true);
1062  }
1063  else
1064  {
1065  return(false);
1066  }
1067 }
1068 
1069 // ---------------------------------------------------------------------------
1070 
1072 /*
1073  Set != operator when any of TrackVectorPosition, ELink or XLink different
1074 */
1075 {
1076  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1077  {
1078  return(false);
1079  }
1080  else
1081  {
1082  return(true);
1083  }
1084 }
1085 
1086 // ---------------------------------------------------------------------------
1087 // Track functions
1088 // ---------------------------------------------------------------------------
1089 
1090 // ---------------------------------------------------------------------------
1091 
1092 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1093 {
1094  TypeOfRoute = 0;
1095  ReducedTimePenalty = false;
1096  BarrierState = Up;
1097  ChangeDuration = 0.0;
1098  BaseElementSpeedTag = 1;
1099  HLoc = 0;
1100  VLoc = 0;
1101  StartTime = TDateTime(0);
1102 }
1103 
1104 // ---------------------------------------------------------------------------
1105 
1107 {
1108 // CurrentSpeedButtonTag = 0; //not assigned yet
1109 
1110  HLocMin = 2000000000;
1111  VLocMin = 2000000000;
1112  HLocMax = -2000000000;
1113  VLocMax = -2000000000;
1114  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1115  CopyFlag = false; // only true for copying, so names aren't copied
1116 
1117  AnsiString NL = '\n';
1118 
1119  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1120  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1121  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1122  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1123 
1128 
1129  int InternalLinkCheckArray[9][2] =
1130  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1131 
1132 /* array of valid link values for 'old' location and 'new' location, where
1133  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1134 
1135  for(int x = 0; x < 9; x++)
1136  {
1137  for(int y = 0; y < 2; y++)
1138  {
1139  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1140  }
1141  }
1142 
1143 // Platform and default track element values
1144  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1145 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1146  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1147  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1148  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1149  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1150  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1151  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1152  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1153  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1154 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1155 
1156  int HVArray[10][2] =
1157  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1158 
1159  for(int x = 0; x < 10; x++)
1160  {
1161  for(int y = 0; y < 2; y++)
1162  {
1163  LinkHVArray[x][y] = HVArray[x][y];
1164  }
1165  }
1166  TrackFinished = false;
1167 // DistancesSet = false;
1168 
1169  TSigElement TempSigTable[40] = // original four aspect
1170  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1171  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1172 
1173  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1174  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1175 
1178 
1179  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1180  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1181 
1182  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1183  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1184  {75, 4, RailGraphics->gl75}};
1185 
1186  for(int x = 0; x < 40; x++)
1187  {
1188  SigTable[x] = TempSigTable[x];
1189  }
1190 
1191  TSigElement TempSigTableThreeAspect[40] =
1192  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1193  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1194 
1195  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1196  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1197 
1198  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1199  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1200 
1201  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1202  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1203 
1204  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1205  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1206  {75, 4, RailGraphics->gl75}};
1207 
1208  for(int x = 0; x < 40; x++)
1209  {
1210  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1211  }
1212 
1213  TSigElement TempSigTableTwoAspect[40] =
1214  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1215  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1216 
1217  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1218  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1219 
1220  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1221  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1222 
1223  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1224  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1225 
1226  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1227  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1228  {75, 4, RailGraphics->gl75}};
1229 
1230  for(int x = 0; x < 40; x++)
1231  {
1232  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1233  }
1234 
1235  TSigElement TempSigTableGroundSignal[40] =
1239 
1243 
1247 
1251 
1252  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1255 
1256  for(int x = 0; x < 40; x++)
1257  {
1258  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1259  }
1260 
1261 /*
1262  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1263  a single location. These are as follows:-
1264  Directly Adjacent = up, down, left or right - NOT diagonal.
1265  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1266  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1267  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1268 
1269  //t 76
1270  //b 77
1271  //l 78
1272  //r 79
1273  //c 96
1274  //v fb 129
1275  //h fb 130
1276  //v underpass 145
1277  //h underpass 146
1278  //n 131
1279 */
1280 
1281  int Tag76[25][3] =
1282  {{-1, 0, 96}, // c top plat
1283  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1284  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1285  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1286  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1287  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1288  {0, 0, 129}, {0, -1, 145}, // v up
1289  {0, 0, 145}};
1290 
1291  for(int x = 0; x < 25; x++)
1292  {
1293  for(int y = 0; y < 3; y++)
1294  {
1295  Tag76Array[x][y] = Tag76[x][y];
1296  }
1297  }
1298 
1299  int Tag77[25][3] =
1300  {{-1, 0, 96}, // c bot plat
1301  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1302  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1303  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1304  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1305  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1306  {0, 0, 129}, {0, 1, 145}, // v up
1307  {0, 0, 145}};
1308 
1309  for(int x = 0; x < 25; x++)
1310  {
1311  for(int y = 0; y < 3; y++)
1312  {
1313  Tag77Array[x][y] = Tag77[x][y];
1314  }
1315  }
1316 
1317  int Tag78[25][3] =
1318  {{-1, 0, 96}, // c left plat
1319  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1320  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1321  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1322  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1323  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1324  {0, 0, 130}, {-1, 0, 146}, // h up
1325  {0, 0, 146}};
1326 
1327  for(int x = 0; x < 25; x++)
1328  {
1329  for(int y = 0; y < 3; y++)
1330  {
1331  Tag78Array[x][y] = Tag78[x][y];
1332  }
1333  }
1334 
1335  int Tag79[25][3] =
1336  {{-1, 0, 96}, // c right plat
1337  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1338  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1339  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1340  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1341  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1342  {0, 0, 130}, {1, 0, 146}, // h up
1343  {0, 0, 146}};
1344 
1345  for(int x = 0; x < 25; x++)
1346  {
1347  for(int y = 0; y < 3; y++)
1348  {
1349  Tag79Array[x][y] = Tag79[x][y];
1350  }
1351  }
1352 
1353  int Tag96[28][3] =
1354  {{-1, 0, 96}, // c //concourse
1355  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1356  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1357  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1358  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1359  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1360  {0, -1, 129}, {1, 0, 130}, // h fb
1361  {-1, 0, 130}, {0, 1, 145}, // v up
1362  {0, -1, 145}, {1, 0, 146}, // h up
1363  {-1, 0, 146}};
1364 
1365  for(int x = 0; x < 28; x++)
1366  {
1367  for(int y = 0; y < 3; y++)
1368  {
1369  Tag96Array[x][y] = Tag96[x][y];
1370  }
1371  }
1372 
1373  int Tag129[8][3] = // vert fb
1374  {{0, -1, 96}, // c
1375  {0, -1, 77}, // b
1376  {0, -1, 129}, // v fb
1377 
1378  {0, 1, 96}, // c
1379  {0, 1, 76}, // t
1380  {0, 1, 129}, // v fb
1381 
1382  {0, 0, 76}, // t
1383  {0, 0, 77}}; // b
1384 
1385  for(int x = 0; x < 8; x++)
1386  {
1387  for(int y = 0; y < 3; y++)
1388  {
1389  Tag129Array[x][y] = Tag129[x][y];
1390  }
1391  }
1392 
1393  int Tag145[8][3] = // vert up
1394  {{0, -1, 96}, // c
1395  {0, -1, 77}, // b
1396  {0, -1, 145}, // v fb
1397 
1398  {0, 1, 96}, // c
1399  {0, 1, 76}, // t
1400  {0, 1, 145}, // v fb
1401 
1402  {0, 0, 76}, // t
1403  {0, 0, 77}}; // b
1404 
1405  for(int x = 0; x < 8; x++)
1406  {
1407  for(int y = 0; y < 3; y++)
1408  {
1409  Tag145Array[x][y] = Tag145[x][y];
1410  }
1411  }
1412 
1413  int Tag130[8][3] = // hor fb
1414  {{-1, 0, 96}, // c
1415  {-1, 0, 79}, // r
1416  {-1, 0, 130}, // h fb
1417 
1418  {1, 0, 96}, // c
1419  {1, 0, 78}, // l
1420  {1, 0, 130}, // h fb
1421 
1422  {0, 0, 78}, // l
1423  {0, 0, 79}}; // r
1424 
1425  for(int x = 0; x < 8; x++)
1426  {
1427  for(int y = 0; y < 3; y++)
1428  {
1429  Tag130Array[x][y] = Tag130[x][y];
1430  }
1431  }
1432 
1433  int Tag146[8][3] = // hor up
1434  {{-1, 0, 96}, // c
1435  {-1, 0, 79}, // r
1436  {-1, 0, 146}, // h fb
1437 
1438  {1, 0, 96}, // c
1439  {1, 0, 78}, // l
1440  {1, 0, 146}, // h fb
1441 
1442  {0, 0, 78}, // l
1443  {0, 0, 79}}; // r
1444 
1445  for(int x = 0; x < 8; x++)
1446  {
1447  for(int y = 0; y < 3; y++)
1448  {
1449  Tag146Array[x][y] = Tag146[x][y];
1450  }
1451  }
1452 
1453  int Tag131[4][3] =
1454  {{-1, 0, 131}, // n
1455  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1456 
1457  for(int x = 0; x < 4; x++)
1458  {
1459  for(int y = 0; y < 3; y++)
1460  {
1461  Tag131Array[x][y] = Tag131[x][y];
1462  }
1463  }
1464 
1465  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1466  {
1467  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1468  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1469  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1470  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1471  140, 144, 145, 146
1472  };
1473 
1474  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1475  {
1476  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1477  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1478  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1479  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1480  141, 144, 145, 146
1481  };
1482 
1483  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1484  {
1485  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1486  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1487  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1488  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1489  141, 144, 146, 145
1490  };
1491 
1492  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1493  {
1494  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1495  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1496  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1497  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1498  140, 144, 146, 145
1499  };
1500 
1501  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1502  {
1503  FlipArray[x] = InternalFlipArray[x];
1504  MirrorArray[x] = InternalMirrorArray[x];
1505  RotRightArray[x] = InternalRotRightArray[x];
1506  RotLeftArray[x] = InternalRotLeftArray[x];
1507  }
1508 }
1509 
1510 // ---------------------------------------------------------------------------
1512 {
1513 // delete TrackVectorPtr;
1514 // delete FixedTrackArrayPtr;
1515  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1516 
1517  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1518  {
1519  delete UGMIt->second;
1520  UGMIt++;
1521  }
1522  delete GapFlashGreen;
1523  delete GapFlashRed;
1524  // all the rest are cleared by the relevant automatic destructors
1525 }
1526 
1527 // ---------------------------------------------------------------------------
1528 
1530 {
1531  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1532  {
1533 // loc 0 not used, set to bmSolidBgnd
1537 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1557  };
1558 
1559  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1560  {
1561 // loc 0 not used, set to smSolidBgnd
1565 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1584  RailGraphics->smTransparent, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1585  };
1586 
1587 // track types
1588  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1589  {
1590  Erase, // 1 0
1591  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1592  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1593  Crossover, Crossover, // 2 15-16
1594  Unused, // 17 (was for text in earlier development) //1 17
1597  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1601  Platform, Platform, Platform, Platform, // 4 76-79
1604  Concourse, // 1 96
1607  Simple, Simple, Simple, Simple, // 4 125-128
1608  FootCrossing, FootCrossing, // 2 129-130
1609  NamedNonStationLocation, // 1 131
1610  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1611  Simple, Simple, Simple, Simple, // 4 140-143
1612  LevelCrossing, // 1 144
1613  FootCrossing, FootCrossing // 2 145 & 146
1614  };
1615 
1616 // links
1617  int Links[FirstUnusedSpeedTagNumber][4] =
1618  {{-1, -1, -1, -1}, // erase element
1619  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1620  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1621 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1622  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1623  {-1, -1, -1, -1}, // unused
1624  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1625  {2, 7, -1, -1}, // simple
1626  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1627 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1628 // (or right diverging if no straight)
1629  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1630  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1631  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1632  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1633  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1634  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1635  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1636  {-1, -1, -1, -1}, // Concourse
1637  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1638  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1639  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1640  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1641  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1642  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1643  {-1, -1, -1, -1}, // NamedNonStationLocation
1644  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1645 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1646  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1647  {-1, -1, -1, -1}, // level crossing
1648  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1649  };
1650 
1652  {{NotSet, NotSet, NotSet, NotSet}, // unused
1656  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1658  {NotSet, NotSet, NotSet, NotSet}, // unused
1662  {Connection, Connection, NotSet, NotSet}, // simple
1666  {Lead, Trail, Lead, Trail}, // points
1668  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1676  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1682  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1691  {Connection, Connection, NotSet, NotSet}, // Arrows
1693  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1695  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1697  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1698  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1699  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1700  };
1701 
1702  for(int x = 0; x < 17; x++)
1703  {
1704  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1705  }
1706  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1707 // 17 was the old text value so don't want any graphics (now disused)
1708  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1709  {
1710  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1711  }
1712 }
1713 
1714 // ---------------------------------------------------------------------------
1715 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1716  ExistingGraphicLoaded(false), Width(16), Height(16)
1717 {
1718  OriginalGraphic = new Graphics::TBitmap;
1719  OriginalGraphic->PixelFormat = pf8bit;
1720  OriginalGraphic->Width = Width;
1721  OriginalGraphic->Height = Height;
1722  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1723 }
1724 
1725 // ---------------------------------------------------------------------------
1726 
1727 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1728  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1729 {
1730  OriginalGraphic = new Graphics::TBitmap;
1731  OriginalGraphic->PixelFormat = pf8bit;
1732  OriginalGraphic->Width = Width;
1733  OriginalGraphic->Height = Height;
1734  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1735 }
1736 
1737 // ---------------------------------------------------------------------------
1738 
1740 {
1741  delete OriginalGraphic;
1742 }
1743 
1744 // ---------------------------------------------------------------------------
1745 
1746 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1747 {
1748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1749  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1750  VPos = VPosIn;
1751  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1752 
1753  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1754  SourceRect.init(Left, Top, Left + Width, Top + Height);
1755  ScreenSourceSet = true;
1756  Utilities->CallLogPop(422);
1757 }
1758 
1759 // ---------------------------------------------------------------------------
1760 
1762 {
1763  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1764  if(!OverlayLoaded)
1765  {
1766  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1767  }
1768  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1769  {
1770  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1771  }
1772  if(!ScreenSourceSet)
1773  {
1774  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1775  }
1776  if(ExistingGraphicLoaded) // can only call one of the load functions
1777  {
1778  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1779  }
1780  if(OverlayPlotted) // don't load from screen if overlay plotted
1781  {
1782  Utilities->CallLogPop(775);
1783  return;
1784  }
1785  TRect DestRect(0, 0, Width, Height);
1786 
1788  OriginalLoaded = true;
1789  ScreenGraphicLoaded = true;
1790  Utilities->CallLogPop(423);
1791 }
1792 
1793 // ---------------------------------------------------------------------------
1794 
1795 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1796 /*
1797  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1798 */
1799 {
1800  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1801  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1802  if(!OverlayLoaded)
1803  {
1804  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1805  }
1806  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1807  {
1808  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1809  }
1810  if(ScreenGraphicLoaded) // can only call one of the load functions
1811  {
1812  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1813  }
1814  Width = WidthIn;
1815  Height = HeightIn;
1816  OriginalGraphic->Width = Width;
1817  OriginalGraphic->Height = Height;
1818  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1819  VPos += VOffset;
1820  TRect DestRect(0, 0, Width, Height);
1821 
1822  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1823  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1824  OriginalLoaded = true;
1825  ExistingGraphicLoaded = true;
1826  Utilities->CallLogPop(424);
1827 }
1828 
1829 // ---------------------------------------------------------------------------
1830 
1831 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1832 {
1833  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1834  OverlayGraphic = Overlay;
1835  OverlayLoaded = true;
1836  Utilities->CallLogPop(425);
1837 }
1838 
1839 // ---------------------------------------------------------------------------
1840 
1842 {
1843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1844  if(!OverlayLoaded)
1845  {
1846  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1847  }
1848  if(!OverlayPlotted)
1849  {
1850  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1851  Disp->Update();
1852  OverlayPlotted = true;
1853  }
1854  Utilities->CallLogPop(426);
1855 }
1856 
1857 // ---------------------------------------------------------------------------
1858 
1860 {
1861  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1862  if(OverlayPlotted)
1863  {
1864  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1865  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1866  {
1867  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1868  }
1869  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1870  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1871  OverlayPlotted = false;
1872  }
1873  Utilities->CallLogPop(427);
1874 }
1875 
1876 // ---------------------------------------------------------------------------
1877 
1879 {
1880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1881  bool TrackPresent = false;
1882 
1883  if(InactiveTrackVector.size() != 0)
1884  {
1885  Utilities->CallLogPop(1333);
1886  return(false);
1887  }
1888  else if(TrackVector.size() == 0)
1889  {
1890  Utilities->CallLogPop(1334);
1891  return(true);
1892  }
1893  else
1894  {
1895  for(unsigned int x = 0; x < TrackVector.size(); x++)
1896  {
1897  if((TrackVector.at(x).SpeedTag != 0))
1898  {
1899  TrackPresent = true;
1900  }
1901  }
1902  }
1903  Utilities->CallLogPop(1335);
1904  return(!TrackPresent);
1905 }
1906 
1907 // ---------------------------------------------------------------------------
1908 
1909 bool TTrack::NoActiveTrack(int Caller)
1910 {
1911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1912  bool TrackPresent = false;
1913 
1914  if(TrackVector.size() == 0)
1915  {
1916  Utilities->CallLogPop(1582);
1917  return(true);
1918  }
1919  else
1920  {
1921  for(unsigned int x = 0; x < TrackVector.size(); x++)
1922  {
1923  if((TrackVector.at(x).SpeedTag != 0))
1924  {
1925  TrackPresent = true;
1926  }
1927  break;
1928  }
1929  }
1930  Utilities->CallLogPop(1583);
1931  return(!TrackPresent);
1932 }
1933 
1934 // ---------------------------------------------------------------------------
1935 
1936 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1937 {
1938  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1939  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1940  TrackEraseSuccessfulFlag = false;
1941 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1942 // since have to match platforms as well as track
1943 // used to set TrackFinished to false if an element erased
1944 
1945  ErasedTrackVectorPosition = -1; // marker for no element erased
1946  AnsiString SName = "", ErrorString;
1948  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1949  TTrackMapIterator TrackMapPtr;
1950  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1951 
1952  if(TrackVector.size() != 0)
1953  {
1954  TrackMapKeyPair.first = HLocInput;
1955  TrackMapKeyPair.second = VLocInput;
1956  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1957  if(TrackMapPtr != TrackMap.end())
1958  {
1959  bool FoundFlag;
1960  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1961  if(FoundFlag) // should find it as it's in the map
1962  {
1963  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1964  {
1965  SName = TrackElementAt(1, VecPos).LocationName;
1966  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1967  if(ErrorString != "")
1968  {
1969  throw Exception(ErrorString + " for EraseTrackElement 1");
1970  }
1971  LocationNameMultiMap.erase(SNIt);
1972  }
1973  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1974  // ensure erase vector element before map element as iterator no longer valid after a map erase
1975  TrackMap.erase(TrackMapPtr);
1976  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1977  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1979  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1980  if(SName != "")
1981  {
1982  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1983  int HPos, VPos;
1984  if(TextHandler->FindText(1, SName, HPos, VPos))
1985  {
1986  if(TextHandler->TextErase(5, HPos, VPos, SName))
1987  {
1988  ;
1989  } // condition not used
1990 
1991  }
1992  }
1993  ErasedTrackVectorPosition = VecPos;
1994  TrackEraseSuccessfulFlag = true;
1995  }
1996  }
1997  }
1998  if(InactiveTrackVector.size() != 0)
1999  {
2000  unsigned int VecPos;
2001  InactiveTrackMapKeyPair.first = HLocInput;
2002  InactiveTrackMapKeyPair.second = VLocInput;
2003  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2004  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2005  {
2006  SName = "";
2007  VecPos = InactiveTrack2MultiMapIterator->second;
2008  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2009  {
2010  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2011  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2012  if(ErrorString != "")
2013  {
2014  throw Exception(ErrorString + " for EraseTrackElement 2A");
2015  }
2016  LocationNameMultiMap.erase(SNIt);
2017  }
2018  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2019  // ensure erase vector element before map element as iterator no longer valid after a map erase
2020  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2021  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2022  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2024  TrackEraseSuccessfulFlag = true;
2025  if(SName != "")
2026  {
2027  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2028  int HPos, VPos;
2029  if(TextHandler->FindText(2, SName, HPos, VPos))
2030  {
2031  if(TextHandler->TextErase(6, HPos, VPos, SName))
2032  {
2033  ;
2034  } // condition not used
2035 
2036  }
2037  }
2038  }
2039  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2040  {
2041  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2042  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2043  {
2044  SName = "";
2045  VecPos = InactiveTrack2MultiMapIterator->second;
2046  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2047  {
2048  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2049  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2050  if(ErrorString != "")
2051  {
2052  throw Exception(ErrorString + " for EraseTrackElement 2B");
2053  }
2054  LocationNameMultiMap.erase(SNIt);
2055  }
2056  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2057  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2058  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2060  if(SName != "")
2061  {
2062  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2063  int HPos, VPos;
2064  if(TextHandler->FindText(3, SName, HPos, VPos))
2065  {
2066  if(TextHandler->TextErase(7, HPos, VPos, SName))
2067  {
2068  ;
2069  } // condition not used
2070 
2071  }
2072  }
2073  }
2074  }
2075  }
2076  if(TrackEraseSuccessfulFlag)
2077  {
2078  CalcHLocMinEtc(2);
2079  SetTrackFinished(false);
2080  }
2081  if(InternalChecks)
2082  {
2083  CheckMapAndTrack(1); // test
2084  CheckMapAndInactiveTrack(1); // test
2085  CheckLocationNameMultiMap(6); // test
2086  }
2087  Utilities->CallLogPop(428);
2088 }
2089 
2090 // ---------------------------------------------------------------------------
2091 
2092 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2093 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2094 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2095 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2096 {
2097  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2098  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2099  bool PlatAllowedFlag = false;
2100 
2101  TrackLinkingRequiredFlag = false;
2102 /*
2103  Not erase, that covered separately.
2104  First check if Current SpeedButton assigned, then check if a platform and only
2105  permit if an appropriate trackpiece already there & not a same platform there.
2106  - can't enter a platform without track first.
2107  Then for non-platforms, check if a track piece already present at location &
2108  reject if so.
2109 */
2110 
2111  TLocationNameMultiMapEntry LocationNameEntry;
2112 
2113  LocationNameEntry.first = "";
2114  if(CurrentTag == 0)
2115  {
2116  Utilities->CallLogPop(429);
2117  return; // not assigned yet
2118  }
2119  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2120 
2121  TempTrackElement.HLoc = HLocInput;
2122  TempTrackElement.VLoc = VLocInput;
2123  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2124 // new at version 0.6 - set signal aspect depending on build mode
2125 
2126  if(TempTrackElement.TrackType == SignalPost)
2127  {
2128  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2129  // pasting a SignalPost can only have values 1 to 4
2130  {
2132  {
2133  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2134  }
2136  {
2137  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2138  }
2140  {
2141  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2142  }
2143  else
2144  {
2145  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2146  }
2147  }
2148  else if(Aspect == 1)
2149  {
2150  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2151  }
2152  else if(Aspect == 2)
2153  {
2154  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2155  }
2156  else if(Aspect == 3)
2157  {
2158  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2159  }
2160  else
2161  {
2162  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2163  }
2164  }
2165  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2166  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2167  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2168  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2169 
2170  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2171  {
2173  {
2174  NonStationOrLevelCrossingPresent = true;
2175  }
2176  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2177  {
2178  NonStationOrLevelCrossingPresent = true;
2179  }
2180  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2181  {
2182  PlatformPresent = true;
2183  }
2184  // no need to check IMPair.second since if that exists it is because .first is a platform
2185  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2186  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2187  }
2188 // check platforms
2189  if(TempTrackElement.TrackType == Platform)
2190  {
2191  if(FoundFlag) // active track element already there
2192  {
2193  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2194  {
2195  ;
2196  }
2197  // same platform type already there so above keeps PlatAllowedFlag false
2198  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2199  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2200  {
2201  PlatAllowedFlag = true;
2202  }
2203  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2204  {
2205  PlatAllowedFlag = true;
2206  }
2207  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2208  {
2209  PlatAllowedFlag = true;
2210  }
2211  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2212  {
2213  PlatAllowedFlag = true;
2214  }
2215  if(PlatAllowedFlag)
2216  {
2217  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2218  TrackPush(1, TempTrackElement);
2219  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2220  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2221  // Must be called AFTER TrackPush
2222  // No need to plot the element - Clearand ... called after this function called
2223  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2224  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2225 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2226 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2227 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2228  if(InternalChecks)
2229  {
2230  CheckMapAndInactiveTrack(5); // test
2231  CheckLocationNameMultiMap(4); // test
2232  }
2233  Utilities->CallLogPop(430);
2234  return;
2235  }
2236  } // if(FoundFlag)
2237 
2238  Utilities->CallLogPop(431);
2239  return;
2240  } // if platform
2241 
2242 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2243  if(TempTrackElement.TrackType == NamedNonStationLocation)
2244  {
2245  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2246  (!FoundFlag && !InactiveFoundFlag))
2247  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2248  {
2249  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2250  TrackPush(2, TempTrackElement);
2251  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2252  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2253  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2254  {
2255 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2256 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2257 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2258  }
2259  if(InternalChecks)
2260  {
2261  CheckMapAndInactiveTrack(11); // test
2262  CheckLocationNameMultiMap(12); // test
2263  }
2264  Utilities->CallLogPop(432);
2265  return;
2266  }
2267  else
2268  {
2269  Utilities->CallLogPop(433);
2270  return;
2271  }
2272  }
2273 // check if a level crossing - OK if placed on a plain straight track
2274  if(TempTrackElement.TrackType == LevelCrossing)
2275  {
2276  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2277  {
2278  TrackPush(11, TempTrackElement);
2279  PlotRaisedLinkedLevelCrossingBarriers(0, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2280 // no need for reference to LC element as can't be open
2281  TrackLinkingRequiredFlag = true;
2282  Utilities->CallLogPop(1907);
2283  return;
2284  }
2285  else
2286  {
2287  Utilities->CallLogPop(1906);
2288  return; // was a level crossing but can't place it for some reason
2289  }
2290  }
2291 
2292 // check if another element already there
2293  else if(FoundFlag || InactiveFoundFlag)
2294  {
2295  Utilities->CallLogPop(434);
2296  return; // something already there (active or inactive track)
2297  }
2298 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2299 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2300 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2301 // do this after pushed into vector so that can use EnterLocationName
2302 
2303  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2304  {
2305  TrackPush(3, TempTrackElement);
2306  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2307  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2308  }
2309  else if(TempTrackElement.TrackType == Points)
2310  {
2311  TrackPush(4, TempTrackElement);
2312  bool BothPointFillets = true;
2313  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2314  }
2315  else if(TempTrackElement.TrackType == SignalPost)
2316  {
2317  TrackPush(10, TempTrackElement);
2318  PlotSignal(12, TempTrackElement, Display);
2319  }
2320  else
2321  {
2322  TrackPush(5, TempTrackElement);
2323  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2324  }
2325  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2326  {
2327  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2328  }
2329  if(InternalChecks)
2330  {
2331  CheckMapAndTrack(2); // test
2332  CheckMapAndInactiveTrack(2); // test
2333  CheckLocationNameMultiMap(5); // test
2334  }
2335  Utilities->CallLogPop(2062);
2336 }
2337 
2338 // ---------------------------------------------------------------------------
2339 
2340 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2341  bool InternalChecks)
2342 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2343 {
2344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2345  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2346  bool PlatAllowedFlag = false;
2347 
2348  TrackLinkingRequiredFlag = false;
2349  TLocationNameMultiMapEntry LocationNameEntry;
2350 
2351  LocationNameEntry.first = "";
2352  if(TempTrackElement.SpeedTag == 0)
2353  {
2354  Utilities->CallLogPop(2063);
2355  return; // not assigned yet
2356  }
2357  TempTrackElement.HLoc = HLocInput;
2358  TempTrackElement.VLoc = VLocInput;
2359  for(int x = 0; x < 4; x++) // unset any gaps
2360  {
2361  if(TempTrackElement.Config[x] == Gap)
2362  {
2363  TempTrackElement.ConnLinkPos[x] = -1;
2364  }
2365  TempTrackElement.Conn[x] = -1;
2366  }
2367  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2368 // new at version 0.6 - set signal aspect depending on build mode
2369  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2370  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2371 
2372  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2373  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2374  // for the active track element because these aren't set
2375  // if don't do this then get a mismatch error during map checks later
2376 
2377  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2378 
2379  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2380  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2381 
2382  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2383  {
2384  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2385  {
2386  NonStationOrLevelCrossingPresent = true;
2387  }
2388  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2389  {
2390  NonStationOrLevelCrossingPresent = true;
2391  }
2392  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2393  {
2394  PlatformPresent = true;
2395  }
2396  // no need to check IMPair.second since if that exists it is because .first is a platform
2397  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2398  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2399  }
2400 // check platforms
2401  if(TempTrackElement.TrackType == Platform)
2402  {
2403  if(FoundFlag) // active track element already there
2404  {
2405  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2406  {
2407  ;
2408  }
2409  // same platform type already there so above keeps PlatAllowedFlag false
2410  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2411  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2412  {
2413  PlatAllowedFlag = true;
2414  }
2415  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2416  {
2417  PlatAllowedFlag = true;
2418  }
2419  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2420  {
2421  PlatAllowedFlag = true;
2422  }
2423  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2424  {
2425  PlatAllowedFlag = true;
2426  }
2427  if(PlatAllowedFlag)
2428  {
2429  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2430  TrackPush(12, TempTrackElement);
2431 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2432  {
2433  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2434  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2435  }
2436  // Must be called AFTER TrackPush
2437 // No need to plot the element - Clearand ... called after this function called
2438  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2439  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2440 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2441 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2442 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2443  if(InternalChecks)
2444  {
2445  CheckMapAndInactiveTrack(12); // test
2446  CheckLocationNameMultiMap(20); // test
2447  }
2448  Utilities->CallLogPop(2064);
2449  return;
2450  }
2451  } // if(FoundFlag)
2452 
2453  Utilities->CallLogPop(2065);
2454  return;
2455  } // if platform
2456 
2457 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2458  if(TempTrackElement.TrackType == NamedNonStationLocation)
2459  {
2460  if((FoundFlag && (NameAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2461  (!FoundFlag && !InactiveFoundFlag))
2462  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2463  {
2464  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2465  TrackPush(13, TempTrackElement);
2466 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2467  {
2468  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2469  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2470  }
2471  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2472  {
2473 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2474 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2475 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2476  }
2477  if(InternalChecks)
2478  {
2479  CheckMapAndInactiveTrack(13); // test
2480  CheckLocationNameMultiMap(21); // test
2481  }
2482  Utilities->CallLogPop(2066);
2483  return;
2484  }
2485  else
2486  {
2487  Utilities->CallLogPop(2067);
2488  return;
2489  }
2490  }
2491 // check if a level crossing - OK if placed on a plain straight track
2492  if(TempTrackElement.TrackType == LevelCrossing)
2493  {
2494  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackVector.at(VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2495  {
2496  TrackPush(14, TempTrackElement);
2497  PlotRaisedLinkedLevelCrossingBarriers(3, TrackVector.at(VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2498 // no need for reference to LC element as can't be open
2499  TrackLinkingRequiredFlag = true;
2500  Utilities->CallLogPop(2068);
2501  return;
2502  }
2503  else
2504  {
2505  Utilities->CallLogPop(2069);
2506  return; // was a level crossing but can't place it for some reason
2507  }
2508  }
2509 
2510 // check if another element already there
2511  else if(FoundFlag || InactiveFoundFlag)
2512  {
2513  Utilities->CallLogPop(2070);
2514  return; // something already there (active or inactive track)
2515  }
2516 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2517 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2518 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2519 // do this after pushed into vector so that can use EnterLocationName
2520 
2521  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2522  {
2523  TrackPush(15, TempTrackElement);
2524  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2525  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2526  }
2527  else if(TempTrackElement.TrackType == Points)
2528  {
2529  TrackPush(16, TempTrackElement);
2530  bool BothPointFillets = true;
2531  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2532  }
2533  else if(TempTrackElement.TrackType == SignalPost)
2534  {
2535  TrackPush(17, TempTrackElement);
2536  PlotSignal(14, TempTrackElement, Display);
2537  }
2538  else
2539  {
2540  TrackPush(18, TempTrackElement);
2541  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2542  }
2543  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2544  {
2545  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2546  }
2547  if(InternalChecks)
2548  {
2549  CheckMapAndTrack(12); // test
2550  CheckMapAndInactiveTrack(14); // test
2551  CheckLocationNameMultiMap(22); // test
2552  }
2553  Utilities->CallLogPop(2071);
2554 }
2555 
2556 // ---------------------------------------------------------------------------
2557 
2558 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2559 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2560 // return bool = true for success
2561 // LocError = true for location error & HLoc & VLoc to be inverted
2562 {
2563  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2564  LocError = false;
2565  SetTrackFinished(false);
2566  if(TrackVector.size() == 0)
2567  {
2568  Utilities->CallLogPop(437);
2569  return(false);
2570  }
2571  if(GapsUnset(7))
2572  {
2573  if(GiveMessages)
2574  {
2575  ShowMessage("Gaps must be set before track can be validated");
2576  }
2577  Utilities->CallLogPop(1135);
2578  return(false);
2579  }
2580 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2581 // returns true for any unset gaps
2583  {
2584  // can keep this exception as protected by the GapsUnset call above
2585  throw Exception("Error, gaps unset when TryToConnectTrack called");
2586  }
2588  CheckGapMap(1); // test
2589 // Gap connections now securely defined
2590 
2591  CheckMapAndTrack(8); // test
2592 
2593 // Perform a pre-check prior to TrackMap being compiled
2594  if(GiveMessages)
2595  {
2596  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2597  {
2598  Utilities->CallLogPop(439);
2599  return(false);
2600  }
2601  }
2602  else
2603  {
2604  if(!LinkTrackNoMessages(1, false))
2605  {
2606  Utilities->CallLogPop(1131);
2607  return(false);
2608  }
2609  }
2610 // here if pre-check successful
2611  if(!RepositionAndMapTrack(0))
2612  {
2613  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2614  Utilities->CallLogPop(1138);
2615  return(false);
2616  }
2617 // now perform the final assembly - FinalCall = true
2618  if(GiveMessages)
2619  {
2620  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2621  {
2622  Utilities->CallLogPop(1116);
2623  return(false);
2624  }
2625  }
2626  else
2627  {
2628  if(!LinkTrackNoMessages(2, true))
2629  {
2630  Utilities->CallLogPop(1132);
2631  return(false);
2632  }
2633  }
2634 // success
2635 
2636  PopulateLCVector(0);
2637  CheckGapMap(2); // test
2638  CheckMapAndTrack(3); // test
2639  CheckMapAndInactiveTrack(3); // test
2640  CheckLocationNameMultiMap(9); // test
2641  SetTrackFinished(true);
2642 
2643 // Build ContinuationNameMap
2644  std::pair<AnsiString, char>TempMapPair;
2645 
2646  ContinuationNameMap.clear();
2647  for(int x = 0; x < Track->TrackVectorSize(); x++)
2648  {
2649  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
2650  {
2651  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
2652  TempMapPair.second = 'x'; // unused
2653  ContinuationNameMap.insert(TempMapPair);
2654  }
2655  }
2656  Utilities->CallLogPop(440);
2657  return(true);
2658 }
2659 
2660 // ---------------------------------------------------------------------------
2661 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2662 // unused - too time-consuming - double brute force search
2663 {
2664  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2665  int NewHLoc, NewVLoc;
2666  bool ConnectionFoundFlag, LinkFoundFlag;
2667 
2668  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2669  {
2670  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2671  {
2672  if(TrackVector.at(x).Link[y] <= 0)
2673  {
2674  continue; // no link
2675  }
2676  if(TrackVector.at(x).Config[y] == End)
2677  {
2678  continue; // buffer or continuation
2679  }
2680  if(TrackVector.at(x).Config[y] == Gap)
2681  {
2682  continue; // gap jump
2683  }
2684  // get required H & V for track element joining link 'y'
2685  NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
2686  NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
2687  // find track element if present
2688  ConnectionFoundFlag = false;
2689  for(unsigned int z = 0; z < TrackVector.size(); z++)
2690  {
2691 // if(TrackElementAt(5, z).TrackType == Platform)
2692 // continue; //skip platforms
2693  if((TrackVector.at(z).HLoc == NewHLoc) && (TrackVector.at(z).VLoc == NewVLoc))
2694  {
2695  ConnectionFoundFlag = true;
2696  // find connecting link in the newly found track element if there is one
2697  LinkFoundFlag = false;
2698  for(unsigned int a = 0; a < 4; a++)
2699  {
2700  if(TrackVector.at(z).Link[a] == (10 - TrackVector.at(x).Link[y]))
2701  {
2702  LinkFoundFlag = true;
2703  }
2704  }
2705  // if there isn't a corresponding link set the invert values for the offending element
2706  if(!LinkFoundFlag)
2707  {
2708  HLoc = TrackVector.at(x).HLoc;
2709  VLoc = TrackVector.at(x).VLoc;
2710  Utilities->CallLogPop(441);
2711  return(true);
2712  }
2713  break; // success, so break out of 'z' loop
2714  } // if((TrackVector.at(z).HLoc== NewHLoc) &&....
2715 
2716  } // for z...
2717  // if there isn't a connection set the invert values for the offending element
2718  if(!ConnectionFoundFlag)
2719  {
2720  HLoc = TrackVector.at(x).HLoc;
2721  VLoc = TrackVector.at(x).VLoc;
2722  Utilities->CallLogPop(442);
2723  return(true);
2724  }
2725  } // for y....
2726  } // for x...
2727  Utilities->CallLogPop(443);
2728  return(false); // all OK
2729 }
2730 
2731 // ---------------------------------------------------------------------------
2732 
2733 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2734 {
2735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2736  TrackElement.LogTrack(0));
2737  bool FoundFlag;
2738 
2739  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2740  if(FoundFlag)
2741  {
2742  TrackElement = TrackVector.at(Position);
2743  }
2744  Utilities->CallLogPop(444);
2745  return(FoundFlag);
2746 }
2747 
2748 // ---------------------------------------------------------------------------
2749 
2751 {
2752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2753  if(NextTrackElementPtr >= TrackVector.end())
2754  {
2755  Utilities->CallLogPop(1336);
2756  return(false);
2757  }
2758  Next = *NextTrackElementPtr;
2760  Utilities->CallLogPop(1337);
2761  return(true);
2762 }
2763 
2764 // ---------------------------------------------------------------------------
2765 
2767 {
2768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2770  {
2771  Utilities->CallLogPop(1338);
2772  return(false);
2773  }
2774  Next = *NextTrackElementPtr;
2776  Utilities->CallLogPop(1339);
2777  return(true);
2778 }
2779 
2780 // ---------------------------------------------------------------------------
2781 
2782 int TTrack::NumberOfGaps(int Caller)
2783 
2784 {
2785  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2786  int Count = 0;
2787 
2788  if(TrackVector.size() == 0)
2789  {
2790  Utilities->CallLogPop(1340);
2791  return(0);
2792  }
2793  for(unsigned int x = 0; x < TrackVector.size(); x++)
2794  {
2795  if(TrackVector.at(x).TrackType == GapJump)
2796  {
2797  Count++;
2798  }
2799  }
2800  Utilities->CallLogPop(1341);
2801  return(Count);
2802 }
2803 
2804 // ---------------------------------------------------------------------------
2806 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2807 // returns true for any unset gaps
2808 {
2809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2810  bool UnsetGaps = false;
2811 
2812  if(TrackVector.size() == 0)
2813  {
2814  Utilities->CallLogPop(445);
2815  return(false);
2816  }
2817  for(unsigned int x = 0; x < TrackVector.size(); x++)
2818  {
2819  if(TrackVector.at(x).TrackType != GapJump)
2820  {
2821  for(unsigned int y = 0; y < 4; y++)
2822  {
2823  TrackVector.at(x).Conn[y] = -1;
2824  TrackVector.at(x).ConnLinkPos[y] = -1;
2825  }
2826  }
2827  else // GapJump
2828  {
2829 // int tempint = TrackVector.at(x).Conn[0);
2830 
2831  if(TrackVector.at(x).Conn[0] == -1) // unset if -1
2832  {
2833  for(unsigned int y = 0; y < 4; y++)
2834  {
2835  TrackVector.at(x).Conn[y] = -1;
2836  TrackVector.at(x).ConnLinkPos[y] = -1;
2837  }
2838  UnsetGaps = true;
2839  continue; // to next 'x'
2840  }
2841  else // set, but may not have matching element, or that element may not be set
2842  {
2843  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2844  {
2845  TrackVector.at(x).Conn[y] = -1;
2846  TrackVector.at(x).ConnLinkPos[y] = -1;
2847  }
2848 
2849  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
2850  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2851  {
2852  for(unsigned int y = 0; y < 4; y++)
2853  {
2854  TrackVector.at(x).Conn[y] = -1;
2855  TrackVector.at(x).ConnLinkPos[y] = -1;
2856  }
2857  UnsetGaps = true;
2858  continue; // to next 'x'
2859  }
2860 // here if gap connection is itself a GapJump
2861  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
2862  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2863  // if not clear Conns & CLks & reset Lk[0]
2864  {
2865  for(unsigned int y = 0; y < 4; y++)
2866  {
2867  TrackVector.at(x).Conn[y] = -1;
2868  TrackVector.at(x).ConnLinkPos[y] = -1;
2869  }
2870  UnsetGaps = true;
2871  continue; // to next 'x'
2872  }
2873 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2874 // hence no more action needed on these Conns & CLks
2875  }
2876  } // else //gap jump
2877 
2878  } // for x...
2879  Utilities->CallLogPop(446);
2880  return(UnsetGaps);
2881 }
2882 
2883 // ---------------------------------------------------------------------------
2884 
2885 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2886 {
2887 // VecFile already open and its pointer at right place on calling
2888  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2889  int TempInt;
2890 
2891  TrackClear(1);
2892 // load track elements
2893  int NumberOfActiveElements = 0;
2894 
2895  GraphicsFollow = false;
2896  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2897  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2898 
2899  if(MarkerString[MarkerString.Length()] == '1')
2900  {
2901  GraphicsFollow = true;
2902  }
2903  for(int x = 0; x < NumberOfActiveElements; x++)
2904  {
2905  VecFile >> TempInt; // TrackVectorNumber, not used
2906  VecFile >> TempInt; // SpeedTag
2907  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2908  VecFile >> TempInt;
2909  TrackElement.HLoc = TempInt;
2910  VecFile >> TempInt;
2911  TrackElement.VLoc = TempInt;
2912  if(TrackElement.TrackType == GapJump)
2913  {
2914  VecFile >> TempInt;
2915  TrackElement.ConnLinkPos[0] = TempInt;
2916  VecFile >> TempInt;
2917  TrackElement.Conn[0] = TempInt;
2918  }
2919  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2920  {
2921  VecFile >> TempInt;
2922  TrackElement.Attribute = TempInt;
2923  }
2924  if(TrackElement.TrackType == SignalPost)
2925  {
2926  VecFile >> TempInt;
2927  if(TempInt == 0)
2928  {
2929  TrackElement.CallingOnSet = false;
2930  }
2931  else
2932  {
2933  TrackElement.CallingOnSet = true;
2934  }
2935  }
2936  VecFile >> TempInt;
2937  TrackElement.Length01 = TempInt;
2938  VecFile >> TempInt;
2939  TrackElement.Length23 = TempInt;
2940  VecFile >> TempInt;
2941  if((TempInt != -1) && (TempInt < 10))
2942  {
2943  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2944  }
2945  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2946  {
2947  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2948  }
2949  TrackElement.SpeedLimit01 = TempInt;
2950  VecFile >> TempInt;
2951  if((TempInt != -1) && (TempInt < 10))
2952  {
2953  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
2954  }
2955  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
2956  {
2957  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
2958  }
2959  TrackElement.SpeedLimit23 = TempInt;
2960 
2961  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
2962  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
2963  SetElementID(0, TrackElement);
2964  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
2965 // new for v0.6
2966  if(TrackElement.TrackType == SignalPost)
2967  {
2968  if(Marker[1] == '3')
2969  {
2970  TrackElement.SigAspect = TTrackElement::ThreeAspect;
2971  }
2972  else if(Marker[1] == '2')
2973  {
2974  TrackElement.SigAspect = TTrackElement::TwoAspect;
2975  }
2976  else if(Marker[1] == 'G')
2977  {
2978  TrackElement.SigAspect = TTrackElement::GroundSignal;
2979  }
2980  else
2981  {
2982  TrackElement.SigAspect = TTrackElement::FourAspect;
2983  }
2984  }
2985  if(TrackElement.SpeedTag != 0)
2986  {
2987  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
2988  }
2989  }
2990  int NumberOfInactiveElements = 0;
2991 
2992  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
2993  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
2994  for(int x = 0; x < NumberOfInactiveElements; x++)
2995  {
2996  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
2997  VecFile >> TempInt; // SpeedTag
2998  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2999  VecFile >> TempInt;
3000  TrackElement.HLoc = TempInt;
3001  VecFile >> TempInt;
3002  TrackElement.VLoc = TempInt;
3003  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3004  SetElementID(3, TrackElement);
3005  TrackPush(9, TrackElement);
3006  Utilities->LoadFileString(VecFile); // marker
3007  }
3008  bool LocError = false; // needed for TryToConnectTrack but not used
3009  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3010 
3011  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3012  {
3013  SetTrackFinished(true);
3014  }
3015  else
3016  {
3017  SetTrackFinished(false);
3018  }
3019 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3020 // CheckMapAndInactiveTrack(8);
3021 // CheckLocationNameMultiMap(10);
3022  Utilities->CallLogPop(448);
3023 }
3024 
3025 // ---------------------------------------------------------------------------
3026 
3027 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3028 {
3029 // VecFile already open and its pointer at right place on calling
3030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3031 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3032 // & load into UserGraphicItem then store in UserGraphicVector
3033  UserGraphicVector.clear();
3034  TUserGraphicItem UGI;
3035  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3036 
3037  for(int x = 0; x < NumberOfGraphics; x++)
3038  {
3039  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3040  UGI.HPos = Utilities->LoadFileInt(VecFile);
3041  UGI.VPos = Utilities->LoadFileInt(VecFile);
3042  UGI.Width = 0; // provisional value
3043  UGI.Height = 0; // provisional value
3044  UGI.UserGraphic = NULL; // provisional value
3045  UserGraphicVector.push_back(UGI);
3046  }
3047 // now load the map & set Width, Height & TPicture*
3048  bool FileError = false;
3049 
3050  for(int x = 0; x < NumberOfGraphics; x++)
3051  {
3052  if(FileError)
3053  {
3054  break; // otherwise keeps going round the loop
3055  }
3056  UGI = UserGraphicVectorAt(0, x);
3057  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3058  {
3059  try
3060  {
3061 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3062  UGME.first = UGI.FileName;
3063  UGME.second = new TPicture;
3064  UGME.second->LoadFromFile(UGME.first); // errors caught below
3065  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3066  {
3067  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3068  }
3069  UGI.UserGraphic = UGME.second;
3070  UGI.Width = UGI.UserGraphic->Width;
3071  UGI.Height = UGI.UserGraphic->Height;
3072  UserGraphicVectorAt(1, x) = UGI;
3073  }
3074  catch(const EInvalidGraphic &e)
3075  {
3076  //message already sent in CheckUserGraphics
3077  FileError = true;
3078  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3079  if(!UserGraphicMap.empty())
3080  {
3081  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3082  {
3083  delete UGMIt->second;
3084  }
3085  UserGraphicMap.clear();
3086  }
3087  }
3088  catch(const Exception &e)
3089  {
3090  //message already sent in CheckUserGraphics
3091  FileError = true;
3092  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3093  if(!UserGraphicMap.empty())
3094  {
3095  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3096  {
3097  delete UGMIt->second;
3098  }
3099  UserGraphicMap.clear();
3100  }
3101  }
3102  }
3103  else
3104  {
3105  bool FoundInMap = false;
3106  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3107  {
3108  if(UGI.FileName == UGMIt->first) // already exists in map
3109  {
3110  UGI.UserGraphic = UGMIt->second;
3111  UGI.Width = UGI.UserGraphic->Width;
3112  UGI.Height = UGI.UserGraphic->Height;
3113  UserGraphicVectorAt(2, x) = UGI;
3114  FoundInMap = true;
3115  break;
3116  }
3117  }
3118  if(!FoundInMap)
3119  {
3120  try
3121  {
3123  UGME.first = UGI.FileName;
3124  UGME.second = new TPicture;
3125  UGME.second->LoadFromFile(UGME.first); // errors caught below
3126  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3127  {
3128  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3129  }
3130  UGI.UserGraphic = UGME.second;
3131  UGI.Width = UGI.UserGraphic->Width;
3132  UGI.Height = UGI.UserGraphic->Height;
3133  UserGraphicVectorAt(3, x) = UGI;
3134  }
3135  catch(const EInvalidGraphic &e)
3136  {
3137  //message already sent in CheckUserGraphics
3138  FileError = true;
3139  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3140  if(!UserGraphicMap.empty())
3141  {
3142  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3143  {
3144  delete UGMIt->second;
3145  }
3146  UserGraphicMap.clear();
3147  }
3148  }
3149  catch(const Exception &e)
3150  {
3151  //message already sent in CheckUserGraphics
3152  FileError = true;
3153  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3154  if(!UserGraphicMap.empty())
3155  {
3156  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3157  {
3158  delete UGMIt->second;
3159  }
3160  UserGraphicMap.clear();
3161  }
3162  }
3163  }
3164  }
3165  }
3166  Utilities->CallLogPop(2167);
3167 }
3168 
3169 // ---------------------------------------------------------------------------
3170 
3171 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3172 {
3173 // VecFile already open and its pointer at right place on calling
3174 // if GraphicsFollow true, then save Marker as **Active elements**1
3175 // save trackfinished flag
3176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3177  TTrackElement TrackElement, InactiveTrackElement;
3178 
3179 // save track elements
3180  Utilities->SaveFileInt(VecFile, TrackVector.size());
3181  if(GraphicsFollow)
3182  {
3183  VecFile << "**Active elements**1" << '\0' << '\n';
3184  }
3185  else
3186  {
3187  VecFile << "**Active elements**" << '\0' << '\n';
3188  }
3189  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3190  {
3191  TrackElement = TrackVector.at(x);
3192  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3193  VecFile << TrackElement.SpeedTag << '\n';
3194  VecFile << TrackElement.HLoc << '\n';
3195  VecFile << TrackElement.VLoc << '\n';
3196  if(TrackElement.TrackType == GapJump)
3197  {
3198  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3199  VecFile << TrackElement.Conn[0] << '\n';
3200  }
3201  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3202  {
3203  VecFile << TrackElement.Attribute << '\n';
3204  }
3205  if(TrackElement.TrackType == SignalPost)
3206  {
3207  if(TrackElement.CallingOnSet)
3208  {
3209  VecFile << int(1) << '\n';
3210  }
3211  else
3212  {
3213  VecFile << int(0) << '\n';
3214  }
3215  }
3216  VecFile << TrackElement.Length01 << '\n';
3217  VecFile << TrackElement.Length23 << '\n';
3218  VecFile << TrackElement.SpeedLimit01 << '\n';
3219  VecFile << TrackElement.SpeedLimit23 << '\n';
3220  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3221  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3222 // new for v0.6
3223  if(TrackElement.TrackType == SignalPost)
3224  {
3225  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3226  {
3227  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3228  }
3229  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3230  {
3231  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3232  }
3233  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3234  {
3235  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3236  }
3237  else // 4 aspect
3238  {
3239  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3240  }
3241  }
3242  else
3243  {
3244  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3245  }
3246  }
3247 
3248  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3249  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3250  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3251  {
3252  InactiveTrackElement = InactiveTrackVector.at(x);
3253  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3254  VecFile << InactiveTrackElement.SpeedTag << '\n';
3255  VecFile << InactiveTrackElement.HLoc << '\n';
3256  VecFile << InactiveTrackElement.VLoc << '\n';
3257  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3258  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3259  }
3260  Utilities->CallLogPop(449);
3261 }
3262 
3263 // ---------------------------------------------------------------------------
3264 
3265 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3266 {
3267 // VecFile already open and its pointer at right place on calling
3268 // check trackfinished flag
3269 // inactive elements follow immediately after active elements, no need to check for a marker between them
3270  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3271  int TempInt;
3272 
3273  GraphicsFollow = false;
3274  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3275  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3276  {
3277  Utilities->CallLogPop(1513);
3278  return(false);
3279  }
3280 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3281  AnsiString MarkerString;
3282 
3283  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3284  {
3285  Utilities->CallLogPop(1758);
3286  return(false);
3287  }
3288  if(MarkerString[MarkerString.Length()] == '1')
3289  {
3290  GraphicsFollow = true;
3291  }
3292  for(int x = 0; x < NumberOfActiveElements; x++)
3293  {
3294  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3295  {
3296  Utilities->CallLogPop(1759);
3297  return(false);
3298  }
3299  VecFile >> TempInt;
3300  int SpeedTag = TempInt;
3301  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3302  {
3303  Utilities->CallLogPop(1514);
3304  return(false);
3305  }
3306  VecFile >> TempInt;
3307  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3308  {
3309  Utilities->CallLogPop(1495);
3310  return(false);
3311  }
3312  VecFile >> TempInt;
3313  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3314  {
3315  Utilities->CallLogPop(1497);
3316  return(false);
3317  }
3318  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3319  {
3320  VecFile >> TempInt;
3321  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3322  {
3323  Utilities->CallLogPop(1499);
3324  return(false);
3325  }
3326  VecFile >> TempInt;
3327  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3328  {
3329  Utilities->CallLogPop(1500);
3330  return(false);
3331  }
3332  }
3333  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3334  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3335  {
3336  VecFile >> TempInt;
3337  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3338  {
3339  Utilities->CallLogPop(1502);
3340  return(false);
3341  }
3342  }
3343  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3344  {
3345  VecFile >> TempInt;
3346  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3347  {
3348  Utilities->CallLogPop(1155);
3349  return(false);
3350  }
3351  }
3352  VecFile >> TempInt;
3353  if((TempInt < -1) || (TempInt > 999999)) // Length01
3354  {
3355  Utilities->CallLogPop(1503);
3356  return(false);
3357  }
3358  VecFile >> TempInt;
3359  if((TempInt < -1) || (TempInt > 999999)) // Length23
3360  {
3361  Utilities->CallLogPop(1504);
3362  return(false);
3363  }
3364  VecFile >> TempInt;
3365  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3366  {
3367  Utilities->CallLogPop(1505);
3368  return(false);
3369  }
3370  VecFile >> TempInt;
3371  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3372  {
3373  Utilities->CallLogPop(1506);
3374  return(false);
3375  }
3376  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3377  {
3378  Utilities->CallLogPop(1142);
3379  return(false); // LocationName
3380  }
3381  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3382  {
3383  Utilities->CallLogPop(1143);
3384  return(false); // ActiveTrackElementName
3385  }
3386  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3387  {
3388  Utilities->CallLogPop(1787);
3389  return(false); // marker
3390  }
3391  }
3392  int NumberOfInactiveElements = 0;
3393 
3394  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3395  if(NumberOfInactiveElements < 0) // No of active elements
3396  {
3397  Utilities->CallLogPop(1493);
3398  return(false);
3399  }
3400  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3401  {
3402  Utilities->CallLogPop(1764);
3403  return(false); // **Inactive elements** marker
3404  }
3405  for(int x = 0; x < NumberOfInactiveElements; x++)
3406  {
3407  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3408  {
3409  Utilities->CallLogPop(1765);
3410  return(false);
3411  }
3412  VecFile >> TempInt;
3413  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3414  {
3415  Utilities->CallLogPop(1494);
3416  return(false);
3417  }
3418  VecFile >> TempInt;
3419  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3420  {
3421  Utilities->CallLogPop(1496);
3422  return(false);
3423  }
3424  VecFile >> TempInt;
3425  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3426  {
3427  Utilities->CallLogPop(1498);
3428  return(false);
3429  }
3430  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3431  {
3432  Utilities->CallLogPop(1144);
3433  return(false); // LocationName
3434  }
3435  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3436  {
3437  Utilities->CallLogPop(1788);
3438  return(false); // marker
3439  }
3440  }
3441  Utilities->CallLogPop(1507);
3442  return(true);
3443 }
3444 
3445 // ---------------------------------------------------------------------------
3446 
3447 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3448 {
3449  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3450  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3451 
3452  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3453  {
3454  Utilities->CallLogPop(2168);
3455  return(false);
3456  }
3457  // filename in Graphics folder, then HPos, then VPos
3458  AnsiString FileName = "", TempStr = "";
3459 
3460  for(int x = 0; x < NumberOfGraphics; x++)
3461  {
3462  TPicture *TempPicture = new TPicture;
3463  try
3464  {
3465  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3466  {
3467  Utilities->CallLogPop(2169);
3468  delete TempPicture;
3469  return(false);
3470  }
3471  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3472  delete TempPicture;
3473  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3474  {
3475  Utilities->CallLogPop(2170);
3476  return(false);
3477  }
3478  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3479  {
3480  Utilities->CallLogPop(2171);
3481  return(false);
3482  }
3483  }
3484  catch(const EInvalidGraphic &e)
3485  {
3486  //move file pointer to end of graphic section for later checks in session files
3487  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3488  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3489  for(int y = x + 1; y < NumberOfGraphics; y++)
3490  {
3491  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3492  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3493  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3494  }
3495  ShowMessage(FileName +
3496  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3497  Utilities->CallLogPop(2172);
3498  delete TempPicture;
3499  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3500  }
3501  catch(const Exception &e)
3502  {
3503  //move file pointer to end of graphic section for later checks in session files
3504  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3505  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3506  for(int y = x + 1; y < NumberOfGraphics; y++)
3507  {
3508  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3509  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3510  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3511  }
3512  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3513  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3514  Utilities->CallLogPop(2173);
3515  delete TempPicture;
3516  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3517  }
3518  }
3519  Utilities->CallLogPop(2174);
3520  return(true);
3521 }
3522 
3523 // ---------------------------------------------------------------------------
3524 
3525 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3526 {
3527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3528  int VecSize = Track->BarriersDownVector.size();
3529 
3530  Utilities->SaveFileInt(OutFile, VecSize);
3531  for(int x = 0; x < VecSize; x++)
3532  {
3534  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3535  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3536  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3537  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3538  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3539  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3540  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3541  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3542  }
3543  Utilities->CallLogPop(1963);
3544 }
3545 
3546 // ---------------------------------------------------------------------------
3547 
3548 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3549 {
3550  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3551  int VecSize = Track->ChangingLCVector.size();
3552 
3553  Utilities->SaveFileInt(OutFile, VecSize);
3554  for(int x = 0; x < VecSize; x++)
3555  {
3557  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3558  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3559  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3560  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3561  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3562  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3563  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3564  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3565  }
3566  Utilities->CallLogPop(1980);
3567 }
3568 
3569 // ---------------------------------------------------------------------------
3570 
3571 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3572 {
3573  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3574  int VecSize = Utilities->LoadFileInt(VecFile);
3575 
3576  for(int x = 0; x < VecSize; x++)
3577  {
3578  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3579  {
3580  Utilities->CallLogPop(1970);
3581  return(false);
3582  }
3583  if(!Utilities->CheckFileBool(VecFile))
3584  {
3585  Utilities->CallLogPop(1971);
3586  return(false);
3587  }
3588  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3589  {
3590  Utilities->CallLogPop(1972);
3591  return(false);
3592  }
3593  if(!Utilities->CheckFileDouble(VecFile))
3594  {
3595  Utilities->CallLogPop(1973);
3596  return(false);
3597  }
3598  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3599  {
3600  Utilities->CallLogPop(1974);
3601  return(false);
3602  }
3603  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3604  {
3605  Utilities->CallLogPop(1975);
3606  return(false);
3607  }
3608  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3609  {
3610  Utilities->CallLogPop(1976);
3611  return(false);
3612  }
3613  if(!Utilities->CheckFileDouble(VecFile))
3614  {
3615  Utilities->CallLogPop(1977);
3616  return(false);
3617  }
3618  }
3619  Utilities->CallLogPop(1978);
3620  return(true);
3621 }
3622 
3623 // ---------------------------------------------------------------------------
3624 
3625 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3626 {
3627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3628  int VecSize = Utilities->LoadFileInt(VecFile);
3629 
3630  for(int x = 0; x < VecSize; x++)
3631  {
3632  TActiveLevelCrossing TALC;
3633  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3634  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3635  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3636  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3637  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3638  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3639  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3640  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3641  BarriersDownVector.push_back(TALC);
3642  }
3643  Utilities->CallLogPop(1979);
3644 }
3645 
3646 // ---------------------------------------------------------------------------
3647 
3648 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3649 /*
3650  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3651  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3652  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3653 */
3654 {
3655  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3656  TTrackElement Next;
3657 
3658 // Disp->ClearDisplay();
3660  while(ReturnNextInactiveTrackElement(0, Next))
3661  {
3662  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3663  {
3664  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3665  {
3666  // only plot if on screen, to save time
3667  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3669  {
3670  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3671  }
3672  }
3673  }
3674  }
3675 
3676  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3677 
3678  NextTrackElementPtr = TrackVector.begin();
3679  while(ReturnNextTrackElement(0, Next))
3680  {
3681  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3682  {
3683  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3685  {
3686  if(Next.TrackType == Points)
3687  {
3688  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3689  }
3690  else if(Next.TrackType == SignalPost)
3691  {
3692  PlotSignal(9, Next, Disp);
3693  }
3694  else if(Next.TrackType == GapJump)
3695  {
3696  PlotGap(0, Next, Disp);
3697  }
3698  else
3699  {
3700  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3701  }
3702  }
3703  }
3704  }
3705 
3706  if(BothPointFilletsAndBasicLCs)
3707  {
3709  while(ReturnNextInactiveTrackElement(4, Next))
3710  {
3711  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3712  {
3713  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3714  {
3715  // only plot if on screen, to save time, & OK as plotting one by one here
3716  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3718  {
3719  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3720  {
3721  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3722  }
3723  else
3724  {
3725  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3726  }
3727  }
3728  }
3729  }
3730  }
3731  }
3732  Disp->Update();
3733  Utilities->CallLogPop(468);
3734 }
3735 
3736 // ---------------------------------------------------------------------------
3737 
3738 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3739 {
3740  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3741  if(UserGraphicVector.empty())
3742  {
3743  Utilities->CallLogPop(2175);
3744  return;
3745  }
3746  TUserGraphicItem UGI;
3747 
3748  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3749  {
3750  UGI = UserGraphicVectorAt(4, x);
3751  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3752  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3753  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3754  {
3755  Disp->PlotAndAddUserGraphic(0, UGI);
3756  }
3757  }
3758  Disp->Update();
3759  Utilities->CallLogPop(2176);
3760 }
3761 
3762 // ---------------------------------------------------------------------------
3763 
3764 void TTrack::WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
3765 /*
3766  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3767 */
3768 {
3769  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackToImage");
3770 // need to change graphics back to black on white if have a dark background
3771  TColor OldTransparentColour = Utilities->clTransparent;
3772 
3774  {
3775  Utilities->clTransparent = TColor(0xFFFFFF); // white
3778  }
3779  TTrackElement Next;
3780 
3781  Bitmap->Canvas->CopyMode = cmSrcCopy;
3783  Graphics::TBitmap *GraphicOutput;
3784 
3785  while(ReturnNextInactiveTrackElement(2, Next))
3786  {
3787  GraphicOutput = Next.GraphicPtr;
3788  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3789  {
3790  if(Next.LocationName == "") // plot as named or unnamed (striped)
3791  {
3792  // default is not striped
3793  switch(Next.SpeedTag)
3794  {
3795  case 76: // t platform
3796  GraphicOutput = RailGraphics->gl76Striped;
3797  break;
3798 
3799  case 77: // h platform
3800  GraphicOutput = RailGraphics->bm77Striped;
3801  break;
3802 
3803  case 78: // v platform
3804  GraphicOutput = RailGraphics->bm78Striped;
3805  break;
3806 
3807  case 79: // r platform
3808  GraphicOutput = RailGraphics->gl79Striped;
3809  break;
3810 
3811  case 96: // concourse
3812  GraphicOutput = RailGraphics->ConcourseStriped;
3813  break;
3814 
3815  case 129: // v footbridge
3816  GraphicOutput = RailGraphics->gl129Striped;
3817  break;
3818 
3819  case 130: // h footbridge
3820  GraphicOutput = RailGraphics->gl130Striped;
3821  break;
3822 
3823  case 131: // non-station named loc
3824  GraphicOutput = RailGraphics->bmNameStriped;
3825  break;
3826 
3827  case 145: // v underpass
3828  GraphicOutput = RailGraphics->gl145Striped;
3829  break;
3830 
3831  case 146: // h underpass
3832  GraphicOutput = RailGraphics->gl146Striped;
3833  break;
3834 
3835  default:
3836  GraphicOutput = Next.GraphicPtr;
3837  break;
3838  }
3839  }
3840  if(Next.SpeedTag == 144) // level crossing
3841  {
3842  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3843  {
3844  GraphicOutput = RailGraphics->LCBothVer;
3845  }
3846  else
3847  {
3848  GraphicOutput = RailGraphics->LCBothHor;
3849  }
3850  }
3851  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3852  }
3853  }
3854 
3855  NextTrackElementPtr = TrackVector.begin();
3856  while(ReturnNextTrackElement(2, Next))
3857  {
3858  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3859  {
3860  if(Next.TrackType == Points) // plot both fillets
3861  {
3862  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3863  if(Next.SpeedTag < 28)
3864  {
3865  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3867  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3869  }
3870  else if(Next.SpeedTag < 132)
3871  {
3872  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3873  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3874  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3875  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3876  }
3877  else
3878  {
3879  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3880  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3881  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3882  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3883  }
3884  }
3885  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3886  {
3887  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3888  {
3889  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3890  }
3891  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3892  {
3893  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3894  }
3895  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3896  {
3897  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3898  }
3899  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3900  {
3901  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3902  }
3903  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3904  {
3905  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3906  }
3907  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3908  {
3909  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3910  }
3911  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3912  {
3913  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3914  }
3915  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3916  {
3917  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3918  }
3919  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3920  {
3921  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3922  }
3923  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3924  {
3925  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
3926  }
3927  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
3928  {
3929  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
3930  }
3931  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
3932  {
3933  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
3934  }
3935  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
3936  {
3937  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
3938  }
3939  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
3940  {
3941  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
3942  }
3943  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
3944  {
3945  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
3946  }
3947  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
3948  {
3949  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
3950  }
3951  }
3952  // below added for version 0.6, only stop signals to be drawn
3953  else if(Next.TrackType == SignalPost)
3954  {
3955  for(int x = 0; x < 40; x++)
3956  {
3957  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
3958  {
3959  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
3960  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
3961  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
3962  int HOffset = 0;
3963  if(Next.SpeedTag > 73)
3964  {
3965  HOffset = 5;
3966  }
3967  else if(Next.SpeedTag == 71)
3968  {
3969  HOffset = 9;
3970  }
3971  int VOffset = 0;
3972  if(Next.SpeedTag == 69)
3973  {
3974  VOffset = 9;
3975  }
3976  else if(Next.SpeedTag == 72)
3977  {
3978  VOffset = 5;
3979  }
3980  else if(Next.SpeedTag == 74)
3981  {
3982  VOffset = 5;
3983  }
3984  Graphics::TBitmap *GraphicPtr;
3985  if(Next.SpeedTag > 71)
3986  {
3987  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
3988  }
3989  else if(Next.SpeedTag < 70)
3990  {
3991  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
3992  }
3993  else
3994  {
3995  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
3996  }
3997  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
3998  // plot special signal platform if present
3999  Graphics::TBitmap* SignalPlatformGraphic;
4000  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4001  {
4002  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4003  }
4004  // now plot signal (double yellow overwrites most of signal platform if present)
4005  // below amended for version 0.6
4007  {
4008  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4009  }
4010  else if(Next.SigAspect == TTrackElement::TwoAspect)
4011  {
4012  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4013  }
4014  else if(Next.SigAspect == TTrackElement::GroundSignal)
4015  {
4016  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4017  }
4018  else // 4 aspect
4019  {
4020  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4021  }
4022  break;
4023  }
4024  }
4025  }
4026  else
4027  {
4028  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4029  }
4030  }
4031  }
4032  if(OldTransparentColour != clB5G5R5)
4033  {
4034  Utilities->clTransparent = OldTransparentColour; // restore
4037  }
4038  Utilities->CallLogPop(1533);
4039 }
4040 
4041 // ---------------------------------------------------------------------------
4042 
4043 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4044 {
4045  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4046  if(UserGraphicVector.empty())
4047  {
4048  Utilities->CallLogPop(2192);
4049  return;
4050  }
4051  else
4052  {
4053  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4054  {
4055  Bitmap->Canvas->CopyMode = cmSrcCopy;
4056  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4057  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4058  }
4059  }
4060  Utilities->CallLogPop(2193);
4061 }
4062 
4063 // ---------------------------------------------------------------------------
4064 
4065 void TTrack::WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
4066 /*
4067  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4068  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4069 */
4070 {
4071  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackToImage");
4072 // need to change graphics back to black on white if have a dark background
4073  TColor OldTransparentColour = Utilities->clTransparent;
4074 
4076  {
4077  Utilities->clTransparent = TColor(0xFFFFFF); // white
4080  }
4081  TTrackElement Next;
4082 
4083  Bitmap->Canvas->CopyMode = cmSrcCopy;
4085  Graphics::TBitmap *GraphicOutput;
4086 
4087  while(ReturnNextInactiveTrackElement(3, Next))
4088  {
4089  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4090  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4091  {
4092  if(Next.SpeedTag == 144) // level crossing
4093  {
4094  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4095  if(BaseElement == 1) // hor element
4096  {
4097  if(Next.Attribute == 1) // open to trains
4098  {
4099  GraphicOutput = RailGraphics->LCBothHor;
4100  }
4101  else // plot as closed to trains if in any other state
4102  {
4103  GraphicOutput = RailGraphics->LCBothVer;
4104  }
4105  }
4106  else // vert element
4107  {
4108  if(Next.Attribute == 1) // open to trains
4109  {
4110  GraphicOutput = RailGraphics->LCBothVer;
4111  }
4112  else // plot as closed to trains if in any other state
4113  {
4114  GraphicOutput = RailGraphics->LCBothHor;
4115  }
4116  }
4117  }
4118  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4119  }
4120  }
4121 
4122  NextTrackElementPtr = TrackVector.begin();
4123  while(ReturnNextTrackElement(3, Next))
4124  {
4125  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4126  {
4127  if(Next.TrackType == Points) // plot active fillet
4128  {
4129  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4130  if(Next.SpeedTag < 28)
4131  {
4132  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4134  }
4135  else if(Next.SpeedTag < 132)
4136  {
4137  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4139  }
4140  else
4141  {
4142  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4144  }
4145  }
4146  else if(Next.TrackType == GapJump) // plot as connected
4147  {
4148  if(Next.SpeedTag == 88)
4149  {
4150  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4151  }
4152  else if(Next.SpeedTag == 89)
4153  {
4154  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4155  }
4156  else if(Next.SpeedTag == 90)
4157  {
4158  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4159  }
4160  else if(Next.SpeedTag == 91)
4161  {
4162  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4163  }
4164  else if(Next.SpeedTag == 92)
4165  {
4166  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4167  }
4168  else if(Next.SpeedTag == 93)
4169  {
4170  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4171  }
4172  else if(Next.SpeedTag == 94)
4173  {
4174  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4175  }
4176  else if(Next.SpeedTag == 95)
4177  {
4178  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4179  }
4180  }
4181  else if(Next.TrackType == SignalPost) // plot in correct colour
4182  {
4183  for(int x = 0; x < 40; x++)
4184  {
4185  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4186  {
4187  // plot blank first, then plot platform if present - (always not striped for operating railway)
4188  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4189  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4190  int HOffset = 0;
4191  if(Next.SpeedTag > 73)
4192  {
4193  HOffset = 5;
4194  }
4195  else if(Next.SpeedTag == 71)
4196  {
4197  HOffset = 9;
4198  }
4199  int VOffset = 0;
4200  if(Next.SpeedTag == 69)
4201  {
4202  VOffset = 9;
4203  }
4204  else if(Next.SpeedTag == 72)
4205  {
4206  VOffset = 5;
4207  }
4208  else if(Next.SpeedTag == 74)
4209  {
4210  VOffset = 5;
4211  }
4212  Graphics::TBitmap *GraphicPtr;
4213  if(Next.SpeedTag > 71)
4214  {
4215  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4216  }
4217  else if(Next.SpeedTag < 70)
4218  {
4219  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4220  }
4221  else
4222  {
4223  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4224  }
4225  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4226  // plot special signal platform if present
4227  Graphics::TBitmap* SignalPlatformGraphic;
4228  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4229  {
4230  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4231  }
4232  // now plot signal (double yellow overwrites most of signal platform if present)
4233  // below amended for version 0.6
4235  {
4236  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4237  }
4238  else if(Next.SigAspect == TTrackElement::TwoAspect)
4239  {
4240  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4241  }
4242  else if(Next.SigAspect == TTrackElement::GroundSignal)
4243  {
4244  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4245  }
4246  else // 4 aspect
4247  {
4248  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4249  }
4250  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4251  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4252  {
4253  if(Next.SpeedTag == 68)
4254  {
4255  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4256  }
4257  if(Next.SpeedTag == 69)
4258  {
4259  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4260  }
4261  if(Next.SpeedTag == 70)
4262  {
4263  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4264  }
4265  if(Next.SpeedTag == 71)
4266  {
4267  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4268  }
4269  if(Next.SpeedTag == 72)
4270  {
4271  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4272  }
4273  if(Next.SpeedTag == 73)
4274  {
4275  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4276  }
4277  if(Next.SpeedTag == 74)
4278  {
4279  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4280  }
4281  if(Next.SpeedTag == 75)
4282  {
4283  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4284  }
4285  }
4286  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4287  {
4288  for(int x = 0; x < 40; x++)
4289  {
4290  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4291  {
4292  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4293  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4294  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4295  // plot special signal platform if present
4296  Graphics::TBitmap* SignalPlatformGraphic;
4297  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4298  {
4299  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4300  }
4301  // now plot signal
4302  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4303  break;
4304  }
4305  }
4306  }
4307  break;
4308  }
4309  }
4310  }
4311  else
4312  {
4313  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4314  }
4315  }
4316  }
4317  if(OldTransparentColour != clB5G5R5)
4318  {
4319  Utilities->clTransparent = OldTransparentColour; // restore
4322  }
4323  Utilities->CallLogPop(1701);
4324 }
4325 
4326 // ---------------------------------------------------------------------------
4327 
4328 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4329 {
4330  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4331  for(unsigned int x = 0; x < TrackVector.size(); x++)
4332  {
4333  if(TrackVector.at(x).TrackType == GapJump)
4334  {
4335  if(TrackVector.at(x).Conn[0] > -1)
4336  {
4337  continue; // to next 'x' value as this element has already been set
4338  }
4339  // here if identify a GapJump element not yet set
4340  GapPos = x;
4341  GapHLoc = TrackVector.at(x).HLoc;
4342  GapVLoc = TrackVector.at(x).VLoc;
4343  // highlight it
4345  Utilities->CallLogPop(469);
4346  return(true);
4347  }
4348  }
4349  Utilities->CallLogPop(470);
4350  return(false);
4351 }
4352 
4353 // ---------------------------------------------------------------------------
4354 
4355 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4356 {
4357  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4358  AnsiString(VLoc));
4359  int Position;
4360  TTrackElement TrackElement;
4361 
4362  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4363  {
4364  Utilities->CallLogPop(471);
4365  return(false); // not found
4366  }
4367  if(TrackElement.TrackType != GapJump)
4368  {
4369  Utilities->CallLogPop(472);
4370  return(false); // found something but not a gap
4371  }
4372  if(Position == GapPos)
4373  {
4374  Utilities->CallLogPop(473);
4375  return(false); // selected original gap
4376  }
4377  if(TrackVector.at(Position).Conn[0] != -1)
4378  {
4379  Utilities->CallLogPop(474);
4380  return(false); // already selected
4381  }
4382  TrackVector.at(Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4383  TrackVector.at(Position).ConnLinkPos[0] = 0;
4384  TrackVector.at(GapPos).Conn[0] = Position; // set other one similarly
4385  TrackVector.at(GapPos).ConnLinkPos[0] = 0;
4386 // now highlight the selected location
4387  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4388  Utilities->CallLogPop(475);
4389  return(true);
4390 }
4391 
4392 // ---------------------------------------------------------------------------
4393 
4394 bool TTrack::GapsUnset(int Caller)
4395 // returns true if there are gaps and any are unset
4396 {
4397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4398  if(TrackVector.size() == 0)
4399  {
4400  Utilities->CallLogPop(476);
4401  return(false);
4402  }
4403  for(unsigned int x = 0; x < TrackVector.size(); x++)
4404  {
4405  if(TrackVector.at(x).TrackType == GapJump)
4406  {
4407  if(TrackVector.at(x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4408  {
4409  Utilities->CallLogPop(477);
4410  return(true);
4411  }
4412  else // set, but may not have matching element, or that element may not be set
4413  {
4414  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4415  // check that the element pointed to by the gap link is a GapJump
4416  {
4417  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4418  Utilities->CallLogPop(1137);
4419  return(false);
4420  }
4421 // here if gap connection is itself a GapJump
4422  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4423  // check that the element pointed to by the gap link is a GapJump & that its gap link
4424  // points back to 'x'
4425  {
4426  Utilities->CallLogPop(478);
4427  return(true);
4428  }
4429 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4430  }
4431  } // if(TrackVector.at(x).TrackType == GapJump)
4432 
4433  } // for x...
4434  Utilities->CallLogPop(479);
4435  return(false);
4436 }
4437 
4438 // ---------------------------------------------------------------------------
4439 
4440 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4441 {
4442  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4443  for(unsigned int x = 0; x < TrackVector.size(); x++)
4444  {
4445  if(TrackVector.at(x).TrackType == GapJump)
4446  {
4447  Utilities->CallLogPop(1105);
4448  return(false);
4449  }
4450  }
4451  Utilities->CallLogPop(1106);
4452  return(true);
4453 }
4454 
4455 // ---------------------------------------------------------------------------
4456 
4457 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4458 {
4459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4460  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4461  {
4462  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4463  {
4464  Utilities->CallLogPop(1107);
4465  return(false);
4466  }
4467  }
4468  for(unsigned int x = 0; x < TrackVector.size(); x++)
4469  {
4470  if(TrackVector.at(x).FixedNamedLocationElement)
4471  {
4472  Utilities->CallLogPop(1108);
4473  return(false);
4474  }
4475  }
4476  Utilities->CallLogPop(1109);
4477  return(true);
4478 }
4479 
4480 // ---------------------------------------------------------------------------
4481 
4483 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4484 // returns false otherwise or if there are no NamedLocationElements
4485 {
4486  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4487  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4488  {
4489  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
4490  {
4491  if(InactiveTrackVector.at(x).LocationName == "")
4492  {
4493  Utilities->CallLogPop(1110);
4494  return(true);
4495  }
4496  }
4497  }
4498  for(unsigned int x = 0; x < TrackVector.size(); x++)
4499  {
4500  if(TrackVector.at(x).FixedNamedLocationElement)
4501  {
4502  if(TrackVector.at(x).LocationName == "")
4503  {
4504  Utilities->CallLogPop(1111);
4505  return(true);
4506  }
4507  }
4508  }
4509  Utilities->CallLogPop(1112);
4510  return(false);
4511 }
4512 
4513 // ---------------------------------------------------------------------------
4514 
4515 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4516 {
4517  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4518  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4519  Utilities->CallLogPop(480);
4520 }
4521 
4522 // ---------------------------------------------------------------------------
4523 
4525 {
4526  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4527  if(TrackVector.size() == 0)
4528  {
4529  Utilities->CallLogPop(481);
4530  return;
4531  }
4532  for(unsigned int x = 0; x < TrackVector.size(); x++)
4533  {
4534  if(TrackVector.at(x).TrackType == GapJump)
4535  {
4536  if(TrackVector.at(x).Conn[0] > -1) // set
4537  {
4538  if(TrackVector.at(TrackVector.at(x).Conn[0]).TrackType != GapJump)
4539  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4540  {
4541  TrackVector.at(x).Conn[0] = -1;
4542  TrackVector.at(x).ConnLinkPos[0] = -1;
4543  continue; // to next 'x'
4544  }
4545 // here if gap connection is itself a GapJump
4546  if(TrackVector.at(TrackVector.at(x).Conn[0]).Conn[0] != (int)x)
4547  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4548  // if not clear Conns & CLks
4549  {
4550  TrackVector.at(x).Conn[0] = -1;
4551  TrackVector.at(x).ConnLinkPos[0] = -1;
4552  continue; // to next 'x'
4553  }
4554 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4555 // hence no more action needed on these Conns & CLks
4556  }
4557  } // else //gap jump
4558 
4559  } // for x...
4560 // throw Exception("Test Exception");//test
4561  Utilities->CallLogPop(482);
4562 }
4563 
4564 // ---------------------------------------------------------------------------
4565 
4566 void TTrack::ResetSignals(int Caller)
4567 {
4568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4569  for(unsigned int x = 0; x < TrackVector.size(); x++)
4570  {
4571  if(TrackVector.at(x).TrackType == SignalPost)
4572  {
4573  TrackVector.at(x).Attribute = 0;
4574  }
4575  }
4576  Utilities->CallLogPop(483);
4577 }
4578 
4579 // ---------------------------------------------------------------------------
4580 
4581 void TTrack::ResetPoints(int Caller)
4582 {
4583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4584  for(unsigned int x = 0; x < TrackVector.size(); x++)
4585  {
4586  if(TrackVector.at(x).TrackType == Points)
4587  {
4588  TrackVector.at(x).Attribute = 0;
4589  }
4590  }
4591  Utilities->CallLogPop(484);
4592 }
4593 
4594 // ---------------------------------------------------------------------------
4595 
4596 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4597 {
4598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4599  if(TrackVector.empty())
4600  {
4601  TrackMap.clear();
4602  Utilities->CallLogPop(485);
4603  return(true);
4604  }
4605 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4606  THVPair TrackMapKeyPair;
4607 
4608  NewVector.clear();
4609  TTrackMapIterator TrackMapPtr;
4610 
4611  if(!TrackMap.empty())
4612  {
4613  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4614  {
4615  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4616  }
4617  }
4618  if(NewVector.size() != TrackMap.size())
4619  {
4620  throw Exception("Error - Map & Vector different sizes");
4621  }
4622  unsigned int NonZeroCount = 0;
4623 
4624  for(unsigned int x = 0; x < TrackVector.size(); x++)
4625  {
4626  if(TrackVector.at(x).TrackType != Erase)
4627  {
4628  NonZeroCount++;
4629  }
4630  }
4631  if(NewVector.size() != NonZeroCount)
4632  {
4633  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4634  }
4636  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4637  TTrackMapEntry TrackMapEntry;
4638 
4639  for(unsigned int x = 0; x < TrackVector.size(); x++)
4640  {
4641  TrackMapKeyPair.first = TrackVector.at(x).HLoc;
4642  TrackMapKeyPair.second = TrackVector.at(x).VLoc;
4643  TrackMapEntry.first = TrackMapKeyPair;
4644  TrackMapEntry.second = x;
4645  if(!(TrackMap.insert(TrackMapEntry).second))
4646  {
4647  throw Exception("Error - map insertion failure, TrackVector in error");
4648  }
4649  }
4650 // All track now relocated in TrackVector, reset all Conns & CLks
4651  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4652  {
4653  for(unsigned int y = 0; y < 4; y++)
4654  {
4655  TrackVector.at(x).Conn[y] = -1;
4656  TrackVector.at(x).ConnLinkPos[y] = -1;
4657  }
4658  }
4659  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4660  CheckMapAndTrack(4); // test
4661  CheckMapAndInactiveTrack(4); // test
4662  CheckLocationNameMultiMap(8); // test
4663  if(!ResetGapsFromGapMap(1))
4664  {
4665  Utilities->CallLogPop(489);
4666  return(false);
4667  }
4668  Utilities->CallLogPop(490);
4669  return(true);
4670 }
4671 
4672 // ---------------------------------------------------------------------------
4673 
4674 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4675 {
4676  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4677  GapMap.clear();
4678  THVPair GapMapKeyPair, GapMapValuePair;
4679  TGapMapEntry GapMapEntry;
4680 
4681  for(unsigned int x = 0; x < TrackVector.size(); x++)
4682  {
4683  if(TrackVector.at(x).TrackType == GapJump)
4684  {
4685  GapMapKeyPair.first = TrackVector.at(x).HLoc;
4686  GapMapKeyPair.second = TrackVector.at(x).VLoc;
4687  GapMapEntry.first = GapMapKeyPair;
4688  if(TrackVector.at(x).Conn[0] == -1)
4689  {
4690  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4691  }
4692  GapMapValuePair.first = TrackElementAt(7, TrackVector.at(x).Conn[0]).HLoc;
4693  GapMapValuePair.second = TrackElementAt(8, TrackVector.at(x).Conn[0]).VLoc;
4694  GapMapEntry.second = GapMapValuePair;
4695  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4696  {
4697  GapMap.insert(GapMapEntry);
4698  }
4699  }
4700  }
4701  Utilities->CallLogPop(492);
4702 }
4703 
4704 // ---------------------------------------------------------------------------
4705 
4706 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4707 {
4708  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4709  LocError = false;
4710  bool CheckForLinks = false;
4711 
4712  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4713  {
4714  if(TrackVector.at(x).TrackType == Erase) //Erase isn't used any more as a track type
4715  {
4716  continue; // skip blank elements
4717  }
4718 // check footcrossing linkages
4719  if(TrackVector.at(x).TrackType == FootCrossing)
4720  {
4721  if(!CheckFootCrossingLinks(1, TrackVector.at(x)))
4722  {
4723  ShowMessage(
4724  "Footbridge or underpass connection error. Each end must connect to a platform, concourse or other footbridge or underpass, and they can't connect to each other");
4725  HLoc = TrackVector.at(x).HLoc;
4726  VLoc = TrackVector.at(x).VLoc;
4727  LocError = true;
4728  Utilities->CallLogPop(493);
4729  return(false);
4730  }
4731  }
4732  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4733  {
4734  CheckForLinks = false;
4735  if(TrackVector.at(x).Link[y] <= 0)
4736  {
4737  continue; // no link
4738  }
4739  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4740  {
4741  continue; // buffer
4742  }
4743  if(TrackVector.at(x).Config[y] == Gap)
4744  {
4745  continue; // gaps set later from GapMap
4746 
4747  }
4748  // get required H & V for track element joining link 'y'
4749  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
4750  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
4751  // find track element if present
4752  bool ConnectionFoundFlag;
4753  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4754  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4755  {
4756  ShowMessage("Can't have a track element adjacent to a continuation exit");
4757  HLoc = TrackVector.at(x).HLoc;
4758  VLoc = TrackVector.at(x).VLoc;
4759  LocError = true;
4760  if(FinalCall)
4761  {
4762  throw Exception("Error in final track linkage - continuation adjacent to another element");
4763  }
4764  Utilities->CallLogPop(1539);
4765  return(false);
4766  }
4767  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
4768  {
4769  continue;
4770  }
4771  if(ConnectionFoundFlag)
4772  {
4773  TrackVector.at(x).Conn[y] = VecPos;
4774  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4775  bool LinkFoundFlag = false;
4776  if((TrackVector.at(x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4777  {
4778  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4779  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4780  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4781  }
4782  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover))
4783  && (TrackVector.at(VecPos).TrackType == Buffers))
4784  {
4785  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4786  // need room for a train (2 elements) without fouling points or signals
4787  }
4788  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
4789  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
4790  {
4791  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4792  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4793  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4794  // be named but needs the adjacent element named too
4795  }
4796  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
4797  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
4798  {
4799  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4800  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4801  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4802  }
4803  else if((TrackVector.at(x).Config[y] == Signal) && (TrackVector.at(VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4804  {
4805  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4806  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4807  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4808  }
4809  else if(IsLCAtHV(45, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(46, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
4810  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4811  {
4812  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4813  }
4814  else
4815  {
4816  CheckForLinks = true;
4817  }
4818  if(CheckForLinks)
4819  {
4820  for(unsigned int a = 0; a < 4; a++)
4821  {
4822  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
4823  (TrackVector.at(VecPos).Config[a] != Gap))
4824  {
4825  TrackVector.at(x).ConnLinkPos[y] = a;
4826  // note - this ensures that if the connecting element is a leading point
4827  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4828  // (Points have the same link value for both [0] and [2])
4829  LinkFoundFlag = true;
4830  break; // stop after first find or will find later link for leading point
4831  }
4832  }
4833  }
4834  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4835  if(!LinkFoundFlag)
4836  {
4837  HLoc = TrackVector.at(x).HLoc;
4838  VLoc = TrackVector.at(x).VLoc;
4839  LocError = true;
4840  if(FinalCall)
4841  {
4842  throw Exception("Error in final track linkage - invalid link");
4843  }
4844  Utilities->CallLogPop(494);
4845  return(false);
4846  }
4847  }
4848  // if there isn't a connection set the invert values for the offending element
4849  else // if(ConnectionFoundFlag)
4850  {
4851  HLoc = TrackVector.at(x).HLoc;
4852  VLoc = TrackVector.at(x).VLoc;
4853  LocError = true;
4854  if(FinalCall)
4855  {
4856  throw Exception("Error in final track linkage - connection not found");
4857  }
4858  Utilities->CallLogPop(495);
4859  return(false);
4860  }
4861  }
4862  } // for(unsigned int x=0;x<TrackVector.size();x++)
4863 
4864  if(FinalCall)
4865  {
4867  }
4868 // final check
4869  bool ConnErrorFlag = false;
4870 
4871  for(unsigned int x = 0; x < TrackVector.size(); x++)
4872  {
4873  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
4874  {
4875  ConnErrorFlag = true;
4876  }
4877  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
4878  {
4879  ConnErrorFlag = true;
4880  }
4881  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
4882  {
4883  ConnErrorFlag = true;
4884  }
4885  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
4886  {
4887  ConnErrorFlag = true;
4888  }
4889  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4890  {
4891  if(TrackVector.at(x).ActiveTrackElementName == "")
4892  {
4893  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
4894  {
4895  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4896  }
4897  }
4898  }
4899  }
4900  if(ConnErrorFlag)
4901  {
4902  if(FinalCall)
4903  {
4904  throw Exception("ConnError in LinkTrack - Final");
4905  }
4906  else
4907  {
4908  throw Exception("ConnError in LinkTrack - Precheck");
4909  }
4910  }
4911  bool CLkErrorFlag = false;
4912 
4913  for(unsigned int x = 0; x < TrackVector.size(); x++)
4914  {
4915  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
4916  {
4917  CLkErrorFlag = true;
4918  }
4919  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
4920  {
4921  CLkErrorFlag = true;
4922  }
4923  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
4924  {
4925  CLkErrorFlag = true;
4926  }
4927  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
4928  {
4929  CLkErrorFlag = true;
4930  }
4931  }
4932 
4933  if(CLkErrorFlag)
4934  {
4935  if(FinalCall)
4936  {
4937  throw Exception("CLkError in LinkTrack - Final");
4938  }
4939  else
4940  {
4941  throw Exception("CLkError in LinkTrack - Precheck");
4942  }
4943  }
4944 // set element lengths to min of 20m
4945  for(unsigned int x = 0; x < TrackVector.size(); x++)
4946  {
4947  if(TrackVector.at(x).TrackType == Erase)
4948  {
4949  continue; // skip blank elements
4950  }
4951  if(TrackVector.at(x).Length01 < 20)
4952  {
4953  TrackVector.at(x).Length01 = 20;
4954  }
4955  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
4956  {
4957  TrackVector.at(x).Length23 = 20;
4958  }
4959  }
4960 
4961  if(FinalCall) // ONLY at FinalCall, no point calling twice
4962  {
4963  CalcHLocMinEtc(3);
4964  }
4965  Utilities->CallLogPop(497);
4966  return(true);
4967 }
4968 
4969 // ---------------------------------------------------------------------------
4970 
4971 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
4972 {
4973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
4974  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4975  {
4976  if(TrackVector.at(x).TrackType == Erase)
4977  {
4978  continue; // skip blank elements
4979 
4980  }
4981 // check footcrossing linkages
4982  if(TrackVector.at(x).TrackType == FootCrossing)
4983  {
4984  if(!CheckFootCrossingLinks(3, TrackVector.at(x)))
4985  {
4986  Utilities->CallLogPop(1127);
4987  return(false);
4988  }
4989  }
4990  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4991  {
4992  if(TrackVector.at(x).Link[y] <= 0)
4993  {
4994  continue; // no link
4995  }
4996  if((TrackVector.at(x).TrackType == Buffers) && (TrackVector.at(x).Config[y] == End))
4997  {
4998  continue; // buffer
4999  }
5000  if(TrackVector.at(x).Config[y] == Gap)
5001  {
5002  continue; // gaps set later from GapMap
5003 
5004  }
5005  // get required H & V for track element joining link 'y'
5006  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
5007  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
5008  // find track element if present
5009  bool ConnectionFoundFlag;
5010  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5011  if((TrackVector.at(x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5012  {
5013  if(FinalCall)
5014  {
5015  throw Exception("Error in final track linkage - continuation adjacent to another element");
5016  }
5017  Utilities->CallLogPop(1540);
5018  return(false);
5019  }
5020  if((TrackVector.at(x).TrackType == Continuation) && (TrackVector.at(x).Config[y] == End))
5021  {
5022  continue;
5023  }
5024  if(ConnectionFoundFlag)
5025  {
5026  TrackVector.at(x).Conn[y] = VecPos;
5027  bool LinkFoundFlag = false;
5028  // find connecting link in the newly found track element if there is one & make checks
5029  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
5030  (TrackVector.at(VecPos).TrackType == Buffers))
5031  {
5032  Utilities->CallLogPop(1541);
5033  return(false);
5034  }
5035  else if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover) ||
5036  (TrackVector.at(x).TrackType == Bridge)) && (TrackVector.at(VecPos).TrackType == Continuation))
5037  {
5038  Utilities->CallLogPop(1542);
5039  return(false);
5040  }
5041  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
5042  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
5043  {
5044  Utilities->CallLogPop(1543);
5045  return(false);
5046  }
5047  else if(IsLCAtHV(47, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc) && IsLCAtHV(48, TrackVector.at(VecPos).HLoc, TrackVector.at(VecPos).VLoc))
5048  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5049  {
5050  Utilities->CallLogPop(1981);
5051  return(false);
5052  }
5053 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5054  else if(TrackVector.at(x).TrackType == Continuation)
5055  {
5056  int H = TrackVector.at(x).HLoc;
5057  int V = TrackVector.at(x).VLoc;
5058  bool FoundFlag = false;
5059  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5060  if(FoundFlag)
5061  {
5062  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5063  {
5064  int NewH = TrackElementAt(727, (TrackVector.at(x).Conn[1])).HLoc;
5065  int NewV = TrackElementAt(728, (TrackVector.at(x).Conn[1])).VLoc;
5066  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5067  if(FoundFlag)
5068  {
5069  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5070  {
5071  Utilities->CallLogPop(1544);
5072  return false;
5073  }
5074  }
5075  else
5076  {
5077  Utilities->CallLogPop(1545);
5078  return false;
5079  }
5080  }
5081  }
5082  }
5083 */
5084  for(unsigned int a = 0; a < 4; a++)
5085  {
5086  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
5087  (TrackVector.at(VecPos).Config[a] != Gap))
5088  {
5089  TrackVector.at(x).ConnLinkPos[y] = a;
5090  // note - this ensures that if the connecting element is a leading point
5091  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5092  // (Points have the same link value for both [0] and [2])
5093  LinkFoundFlag = true;
5094  break; // stop after first find or will find later link for leading point
5095  }
5096  }
5097  if(!LinkFoundFlag)
5098  {
5099  if(FinalCall)
5100  {
5101  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5102  }
5103  Utilities->CallLogPop(1128);
5104  return(false);
5105  }
5106  }
5107  else // if(ConnectionFoundFlag)
5108  {
5109  if(FinalCall)
5110  {
5111  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5112  }
5113  Utilities->CallLogPop(1129);
5114  return(false);
5115  }
5116  }
5117  } // for(unsigned int x=0;x<TrackVector.size();x++)
5118 
5119  if(FinalCall)
5120  {
5122  }
5123 // final check
5124  bool ConnErrorFlag = false;
5125 
5126  for(unsigned int x = 0; x < TrackVector.size(); x++)
5127  {
5128  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
5129  {
5130  ConnErrorFlag = true;
5131  }
5132  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
5133  {
5134  ConnErrorFlag = true;
5135  }
5136  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
5137  {
5138  ConnErrorFlag = true;
5139  }
5140  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
5141  {
5142  ConnErrorFlag = true;
5143  }
5144  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5145  {
5146  if(TrackVector.at(x).ActiveTrackElementName == "")
5147  {
5148  if((TrackVector.at(x).StationEntryStopLinkPos1 != -1) || (TrackVector.at(x).StationEntryStopLinkPos2 != -1))
5149  {
5150  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5151  }
5152  }
5153  }
5154  }
5155  if(ConnErrorFlag)
5156  {
5157  if(FinalCall)
5158  {
5159  throw Exception("ConnError in LinkTrack - Final");
5160  }
5161  else
5162  {
5163  throw Exception("ConnError in LinkTrack - Precheck");
5164  }
5165  }
5166  bool CLkErrorFlag = false;
5167 
5168  for(unsigned int x = 0; x < TrackVector.size(); x++)
5169  {
5170  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
5171  {
5172  CLkErrorFlag = true;
5173  }
5174  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
5175  {
5176  CLkErrorFlag = true;
5177  }
5178  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
5179  {
5180  CLkErrorFlag = true;
5181  }
5182  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
5183  {
5184  CLkErrorFlag = true;
5185  }
5186  }
5187 
5188  if(CLkErrorFlag)
5189  {
5190  if(FinalCall)
5191  {
5192  throw Exception("CLkError in LinkTrack - Final");
5193  }
5194  else
5195  {
5196  throw Exception("CLkError in LinkTrack - Precheck");
5197  }
5198  }
5199 // set element lengths to min of 20m
5200  for(unsigned int x = 0; x < TrackVector.size(); x++)
5201  {
5202  if(TrackVector.at(x).TrackType == Erase)
5203  {
5204  continue; // skip blank elements
5205  }
5206  if(TrackVector.at(x).Length01 < 20)
5207  {
5208  TrackVector.at(x).Length01 = 20;
5209  }
5210  if((TrackVector.at(x).Length23 < 20) && (TrackVector.at(x).Length23 != -1))
5211  {
5212  TrackVector.at(x).Length23 = 20;
5213  }
5214  }
5215 
5216  if(FinalCall) // ONLY at FinalCall, no point calling twice
5217  {
5218  CalcHLocMinEtc(7);
5219  }
5220  Utilities->CallLogPop(1130);
5221  return(true);
5222 }
5223 
5224 // ---------------------------------------------------------------------------
5225 
5226 bool TTrack::IsTrackLinked(int Caller) // not used any more
5227 {
5228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5229  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5230  {
5231  if(TrackVector.at(x).TrackType == Erase)
5232  {
5233  Utilities->CallLogPop(498);
5234  return(false);
5235  }
5236 // check foot linkages
5237  if(TrackVector.at(x).TrackType == FootCrossing)
5238  {
5239  if(!CheckFootCrossingLinks(2, TrackVector.at(x)))
5240  {
5241  Utilities->CallLogPop(499);
5242  return(false);
5243  }
5244  }
5245  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5246  {
5247  if(TrackVector.at(x).Link[y] <= 0)
5248  {
5249  continue; // no link
5250  }
5251  if(TrackVector.at(x).Config[y] == End)
5252  {
5253  continue; // buffer or continuation
5254  }
5255  if(TrackVector.at(x).Config[y] == Gap)
5256  {
5257  continue; // gaps set later from GapMap
5258 
5259  }
5260  // get required H & V for track element joining link 'y'
5261  int NewHLoc = TrackVector.at(x).HLoc + LinkHVArray[TrackVector.at(x).Link[y]][0];
5262  int NewVLoc = TrackVector.at(x).VLoc + LinkHVArray[TrackVector.at(x).Link[y]][1];
5263  // find track element if present
5264  bool ConnectionFoundFlag = false;
5265  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5266  if(ConnectionFoundFlag)
5267  {
5268  TrackVector.at(x).Conn[y] = VecPos;
5269  // find connecting link in the newly found track element if there is one & make buffer check
5270  bool LinkFoundFlag = false;
5271  if(((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == SignalPost) || (TrackVector.at(x).TrackType == Crossover)) &&
5272  (TrackVector.at(VecPos).TrackType == Buffers))
5273  {
5274  Utilities->CallLogPop(500);
5275  return(false);
5276  }
5277  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == SignalPost) &&
5278  (TrackVector.at(x).SpeedTag == TrackVector.at(VecPos).SpeedTag))
5279  {
5280  Utilities->CallLogPop(501);
5281  return(false);
5282  }
5283  else if((TrackVector.at(x).TrackType == SignalPost) && (TrackVector.at(VecPos).TrackType == Continuation))
5284  {
5285  Utilities->CallLogPop(502);
5286  return(false);
5287  }
5288  else
5289  {
5290  for(unsigned int a = 0; a < 4; a++)
5291  {
5292  if((TrackVector.at(VecPos).Link[a] == (10 - TrackVector.at(x).Link[y])) && (TrackVector.at(VecPos).Config[a] != End) &&
5293  (TrackVector.at(VecPos).Config[a] != Gap))
5294  {
5295  TrackVector.at(x).ConnLinkPos[y] = a;
5296  // note - this ensures that if the connecting element is a leading point
5297  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5298  // (Points have the same link value for both [0] and [2])
5299  LinkFoundFlag = true;
5300  break; // stop after first find or will find later link for leading point
5301  }
5302  }
5303  }
5304  if(!LinkFoundFlag)
5305  {
5306  Utilities->CallLogPop(503);
5307  return(false);
5308  }
5309  }
5310  else // if(ConnectionFoundFlag)
5311  {
5312  Utilities->CallLogPop(504);
5313  return(false);
5314  }
5315  }
5316  } // for(unsigned int x=0;x<TrackVector.size();x++)
5317 
5318 // final check
5319  bool ConnErrorFlag = false;
5320 
5321  for(unsigned int x = 0; x < TrackVector.size(); x++)
5322  {
5323  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).Conn[0] == -1))
5324  {
5325  ConnErrorFlag = true;
5326  }
5327  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).Conn[1] == -1))
5328  {
5329  ConnErrorFlag = true;
5330  }
5331  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).Conn[2] == -1))
5332  {
5333  ConnErrorFlag = true;
5334  }
5335  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).Conn[3] == -1))
5336  {
5337  ConnErrorFlag = true;
5338  }
5339  }
5340  if(ConnErrorFlag)
5341  {
5342  Utilities->CallLogPop(505);
5343  return(false);
5344  }
5345  bool CLkErrorFlag = false;
5346 
5347  for(unsigned int x = 0; x < TrackVector.size(); x++)
5348  {
5349  if((TrackVector.at(x).Link[0] > 0) && (TrackVector.at(x).Config[0] != End) && (TrackVector.at(x).ConnLinkPos[0] == -1))
5350  {
5351  CLkErrorFlag = true;
5352  }
5353  if((TrackVector.at(x).Link[1] > 0) && (TrackVector.at(x).Config[1] != End) && (TrackVector.at(x).ConnLinkPos[1] == -1))
5354  {
5355  CLkErrorFlag = true;
5356  }
5357  if((TrackVector.at(x).Link[2] > 0) && (TrackVector.at(x).Config[2] != End) && (TrackVector.at(x).ConnLinkPos[2] == -1))
5358  {
5359  CLkErrorFlag = true;
5360  }
5361  if((TrackVector.at(x).Link[3] > 0) && (TrackVector.at(x).Config[3] != End) && (TrackVector.at(x).ConnLinkPos[3] == -1))
5362  {
5363  CLkErrorFlag = true;
5364  }
5365  }
5366 
5367  if(CLkErrorFlag)
5368  {
5369  Utilities->CallLogPop(506);
5370  return(false);
5371  }
5372  Utilities->CallLogPop(507);
5373  return(true);
5374 }
5375 
5376 // ---------------------------------------------------------------------------
5377 
5379 {
5380  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5381  int Position1, Position2;
5382  TTrackElement TrackElement1, TrackElement2;
5383  TGapMapIterator GapMapPtr;
5384 
5385  if(!GapMap.empty())
5386  {
5387  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5388  {
5389  int HLoc1 = GapMapPtr->first.first;
5390  int VLoc1 = GapMapPtr->first.second;
5391  int HLoc2 = GapMapPtr->second.first;
5392  int VLoc2 = GapMapPtr->second.second;
5393  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5394  {
5395  throw Exception("Failed to find H & V for gap1, GapMap in error");
5396  }
5397  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5398  {
5399  throw Exception("Failed to find H & V for gap2, GapMap in error");
5400  }
5401  if(TrackElementAt(9, Position1).TrackType != GapJump)
5402  {
5403  throw Exception("Element at Pos1 not a gap, GapMap in error");
5404  }
5405  if(TrackElementAt(10, Position2).TrackType != GapJump)
5406  {
5407  throw Exception("Element at Pos2 not a gap, GapMap in error");
5408  }
5409  TrackElementAt(11, Position1).Conn[0] = Position2;
5410  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5411  TrackElementAt(13, Position2).Conn[0] = Position1;
5412  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5413  }
5414  }
5415  Utilities->CallLogPop(510);
5416  return(true);
5417 }
5418 
5419 // ---------------------------------------------------------------------------
5420 
5421 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5422 {
5423 // TIMPair MapEntry;
5424  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5425  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5426  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5427  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5428  TLocationNameMultiMapEntry LocationNameEntry;
5429 
5430  LocationNameEntry.first = TrackElement.LocationName;
5431  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5432  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5433  {
5434 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5435 // could arise when loading old railways with multiple NonStationNamedLocs
5436  bool FoundFlag = false;
5437  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5438  if(FoundFlag)
5439  {
5440  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5441  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5442  {
5443  Utilities->CallLogPop(1813);
5444  return;
5445  }
5446  }
5447  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5448  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5449  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5450  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5451  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5452  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5453  if(TrackElement.FixedNamedLocationElement)
5454  {
5455  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5456  LocationNameMultiMap.insert(LocationNameEntry);
5457  }
5458  if(TrackElement.HLoc < HLocMin)
5459  {
5460  HLocMin = TrackElement.HLoc;
5461  }
5462  if(TrackElement.HLoc > HLocMax)
5463  {
5464  HLocMax = TrackElement.HLoc;
5465  }
5466  if(TrackElement.VLoc < VLocMin)
5467  {
5468  VLocMin = TrackElement.VLoc;
5469  }
5470  if(TrackElement.VLoc > VLocMax)
5471  {
5472  VLocMax = TrackElement.VLoc;
5473  }
5474  }
5475  else
5476  {
5477 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5478 // shouldn't arise but leave in as a safeguard
5479  bool FoundFlag = false;
5480  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5481  if(FoundFlag)
5482  {
5483  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5484  {
5485  Utilities->CallLogPop(1814);
5486  return;
5487  }
5488  }
5489  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5490  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5491  {
5492  TrackMapKeyPair.first = TrackElement.HLoc;
5493  TrackMapKeyPair.second = TrackElement.VLoc;
5494  TrackMapEntry.first = TrackMapKeyPair;
5495  TrackMapEntry.second = TrackVector.size() - 1;
5496  TrackMap.insert(TrackMapEntry);
5497  if(TrackElement.FixedNamedLocationElement)
5498  {
5499  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5500  LocationNameMultiMap.insert(LocationNameEntry);
5501  }
5502  if(TrackElement.HLoc < HLocMin)
5503  {
5504  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5505  }
5506  if(TrackElement.HLoc > HLocMax)
5507  {
5508  HLocMax = TrackElement.HLoc;
5509  }
5510  if(TrackElement.VLoc < VLocMin)
5511  {
5512  VLocMin = TrackElement.VLoc;
5513  }
5514  if(TrackElement.VLoc > VLocMax)
5515  {
5516  VLocMax = TrackElement.VLoc;
5517  }
5518  }
5519  }
5520 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5521 // CheckMapAndInactiveTrack(6);//test
5522 
5523 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5524 // with the Platforms until layout fully loaded
5525  Utilities->CallLogPop(511);
5526 }
5527 
5528 // ---------------------------------------------------------------------------
5529 
5530 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5531 {
5532  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5533  AnsiString(VLoc));
5534  THVPair TrackMapKeyPair;
5535 
5536  FoundFlag = false;
5537  TTrackMapIterator TrackMapPtr;
5538 
5539  TrackMapKeyPair.first = HLoc;
5540  TrackMapKeyPair.second = VLoc;
5541  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5542  if(TrackMapPtr == TrackMap.end())
5543  {
5544  Utilities->CallLogPop(512);
5545  return(-1); // nothing found
5546  }
5547  else
5548  {
5549  FoundFlag = true;
5550  Utilities->CallLogPop(513);
5551  return(TrackMapPtr->second);
5552  }
5553 }
5554 
5555 // ---------------------------------------------------------------------------
5556 
5557 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5558 {
5559  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5560  AnsiString(VLoc));
5561  THVPair TrackMapKeyPair;
5562  TTrackMapIterator TrackMapPtr;
5563 
5564  TrackMapKeyPair.first = HLoc;
5565  TrackMapKeyPair.second = VLoc;
5566  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5567  if(TrackMapPtr == TrackMap.end())
5568  {
5569  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5570  throw Exception(Message);
5571  }
5572  else
5573  {
5574  Utilities->CallLogPop(1943);
5575  return(TrackElementAt(871, TrackMapPtr->second));
5576  }
5577 }
5578 
5579 // ---------------------------------------------------------------------------
5580 
5582 {
5583  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5584  AnsiString(VLoc));
5585  THVPair InactiveTrackMapKeyPair;
5586  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5587 
5588  InactiveTrackMapKeyPair.first = HLoc;
5589  InactiveTrackMapKeyPair.second = VLoc;
5590  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5591  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5592  {
5593  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5594  throw Exception(Message);
5595  }
5596  else
5597  {
5598  Utilities->CallLogPop(1949);
5599  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5600  }
5601 }
5602 
5603 // ---------------------------------------------------------------------------
5604 
5605 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5606 {
5607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5608  bool Present = true;
5609  THVPair TrackMapKeyPair;
5610  TTrackMapIterator TrackMapPtr;
5611 
5612  TrackMapKeyPair.first = HLoc;
5613  TrackMapKeyPair.second = VLoc;
5614  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5615  if(TrackMapPtr == TrackMap.end())
5616  {
5617  Present = false;
5618  }
5619  Utilities->CallLogPop(2057);
5620  return(Present);
5621 }
5622 
5623 // ---------------------------------------------------------------------------
5624 
5625 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5626 {
5627  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5628  AnsiString(VLoc));
5629  bool Present = true;
5630  THVPair InactiveTrackMapKeyPair;
5631  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5632 
5633  InactiveTrackMapKeyPair.first = HLoc;
5634  InactiveTrackMapKeyPair.second = VLoc;
5635  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5636  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5637  {
5638  Present = false;
5639  }
5640  Utilities->CallLogPop(2058);
5641  return(Present);
5642 }
5643 
5644 // ---------------------------------------------------------------------------
5645 
5646 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5647 // max number of elements is 2, for platforms
5648 // note that both elements of RetPair may be the same, if only one present in map
5649 {
5650  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5651  AnsiString(VLoc));
5652  THVPair InactiveTrackMapKeyPair;
5653  TIMPair RetPair;
5654  TInactiveTrackRange InactiveTrackRange;
5655 
5656  FoundFlag = false;
5657  InactiveTrackMapKeyPair.first = HLoc;
5658  InactiveTrackMapKeyPair.second = VLoc;
5659  if(InactiveTrack2MultiMap.empty())
5660  {
5661  RetPair.first = 0;
5662  RetPair.second = 0;
5663  Utilities->CallLogPop(1815);
5664  return(RetPair); // map empty
5665  }
5666  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5667  if(InactiveTrackRange.first == InactiveTrackRange.second)
5668  {
5669  RetPair.first = 0;
5670  RetPair.second = 0;
5671  Utilities->CallLogPop(514);
5672  return(RetPair); // nothing found
5673  }
5674  else
5675  {
5676  RetPair.first = InactiveTrackRange.first->second;
5677  RetPair.second = (--InactiveTrackRange.second)->second;
5678  FoundFlag = true;
5679  Utilities->CallLogPop(515);
5680  return(RetPair);
5681  }
5682 }
5683 
5684 // ---------------------------------------------------------------------------
5685 
5686 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5687 {
5688 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5689  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5690  AnsiString(DivergingPosition));
5691  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5692  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5693  int SpeedTag1 = T1.SpeedTag;
5694  int SpeedTag2 = T2.SpeedTag;
5695 
5696  if(T1.Attribute != T2.Attribute)
5697  {
5698  Utilities->CallLogPop(516);
5699  return(false);
5700  }
5701  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5702  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5703  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5704  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5705  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5706  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5707  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5708  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5709  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5710  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5711  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5712  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5713  {
5714  Utilities->CallLogPop(517);
5715  return(true);
5716  }
5717  else
5718  {
5719  Utilities->CallLogPop(518);
5720  return(false);
5721  }
5722 }
5723 
5724 // ---------------------------------------------------------------------------
5725 
5726 /*
5727  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5728  {
5729  if(lower.second < higher.second) return true;
5730  else if(lower.second > higher.second) return false;
5731  else if(lower.second == higher.second)
5732  {
5733  if(lower.first < higher.first) return true;
5734  }
5735  return false;
5736  }
5737 */
5738 // ---------------------------------------------------------------------------
5739 
5740 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5741 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5742 {
5743  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5744  if(TrackElement.TrackType != GapJump)
5745  {
5746  throw Exception("Error, Wrong track type in PlotGap");
5747  }
5748  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5749  {
5750  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5751  }
5752  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5753  {
5754  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5755  }
5756  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5757  {
5758  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5759  }
5760  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5761  {
5762  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5763  }
5764  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5765  {
5766  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5767  }
5768  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5769  {
5770  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5771  }
5772  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5773  {
5774  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5775  }
5776  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5777  {
5778  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5779  }
5780  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5781  {
5782  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5783  }
5784  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5785  {
5786  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5787  }
5788  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5789  {
5790  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5791  }
5792  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5793  {
5794  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5795  }
5796  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5797  {
5798  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5799  }
5800  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5801  {
5802  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5803  }
5804  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5805  {
5806  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5807  }
5808  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5809  {
5810  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5811  }
5812  Utilities->CallLogPop(1101);
5813 }
5814 
5815 // ---------------------------------------------------------------------------
5816 
5817 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5818 {
5819  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5820  if(TrackElement.TrackType != Points)
5821  {
5822  throw Exception("Error, Wrong track type in PlotPoints");
5823  }
5824  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5825  TrackElement.PlotVariableTrackElement(4, Disp);
5826  if(BothFillets)
5827  {
5828  if(TrackElement.SpeedTag < 28)
5829  {
5830  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5831  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5832  }
5833  else if(TrackElement.SpeedTag < 132)
5834  {
5835  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5836  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5837  }
5838  else
5839  {
5840  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5841  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5842  }
5843  }
5844  else
5845  {
5846  if(TrackElement.SpeedTag < 28)
5847  {
5848  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5849  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5850  }
5851  else if(TrackElement.SpeedTag < 132)
5852  {
5853  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5854  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5855  }
5856  else
5857  {
5858  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5859  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5860  }
5861  }
5862 // replot platform if required
5863  TIMPair IMPair;
5864  bool FoundFlag;
5865 
5866  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5867  if(FoundFlag)
5868  {
5869  // only one platform possible at points so only need to plot IMPair.first
5870  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5871  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5872  }
5873  Utilities->CallLogPop(519);
5874 }
5875 
5876 // ---------------------------------------------------------------------------
5877 
5878 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5879 {
5880 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5881  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5882  if(TrackElement.TrackType != SignalPost)
5883  {
5884  throw Exception("Error, Wrong track type in PlotSignal");
5885  }
5886  for(int x = 0; x < 40; x++)
5887  {
5888  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5889  {
5890  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5891  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5892 // in case existing signal is a double yellow
5893  // plot platforms if present
5894 // Graphics::TBitmap* SignalPlatformGraphic;
5895 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5896 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
5897 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
5898 // to not be plotted with the above function.
5899  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
5900  // now plot signal (double yellow overwrites most of signal platform if present)
5901  // additions at version 0.6 for other aspects & ground sigs
5902  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
5903  {
5904  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
5905  }
5906  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
5907  {
5908  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
5909  }
5910  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
5911  {
5912  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5913  }
5914  else // 4 aspect
5915  {
5916  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
5917  }
5918  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
5919  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
5920  {
5921  if(TrackElement.SpeedTag == 68)
5922  {
5923  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
5924  }
5925  if(TrackElement.SpeedTag == 69)
5926  {
5927  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
5928  }
5929  if(TrackElement.SpeedTag == 70)
5930  {
5931  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
5932  }
5933  if(TrackElement.SpeedTag == 71)
5934  {
5935  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
5936  }
5937  if(TrackElement.SpeedTag == 72)
5938  {
5939  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
5940  }
5941  if(TrackElement.SpeedTag == 73)
5942  {
5943  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
5944  }
5945  if(TrackElement.SpeedTag == 74)
5946  {
5947  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
5948  }
5949  if(TrackElement.SpeedTag == 75)
5950  {
5951  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
5952  }
5953  }
5954  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
5955  // ground signal calling on, need to use normal proceed aspect
5956  {
5957  for(int x = 0; x < 40; x++)
5958  {
5959  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
5960  {
5961  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5962  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5963  // plot special signal platform if present
5964  Graphics::TBitmap* SignalPlatformGraphic;
5965  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
5966  // now plot signal
5967  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
5968  }
5969  }
5970  }
5971  break;
5972  }
5973  }
5974  Utilities->CallLogPop(520);
5975 }
5976 
5977 // ---------------------------------------------------------------------------
5978 
5979 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
5980 {
5981  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5982  bool FoundFlag;
5983  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
5984 
5985  if(!FoundFlag)
5986  {
5987  Utilities->CallLogPop(2112);
5988  return;
5989  }
5990  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
5991  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
5992 
5993  // don't want 'else if' for the below as may need to plot 2 platforms
5994  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
5995  {
5996  if(IAElement1.LocationName == "") // '2' will be same
5997  {
5998  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
5999  }
6000  else
6001  {
6002  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6003  }
6004  }
6005  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6006  {
6007  if(IAElement1.LocationName == "") // '2' will be same
6008  {
6009  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6010  }
6011  else
6012  {
6013  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6014  }
6015  }
6016  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6017  {
6018  if(IAElement1.LocationName == "") // '2' will be same
6019  {
6020  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6021  }
6022  else
6023  {
6024  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6025  }
6026  }
6027  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6028  {
6029  if(IAElement1.LocationName == "") // '2' will be same
6030  {
6031  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6032  }
6033  else
6034  {
6035  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6036  }
6037  }
6038  Utilities->CallLogPop(2113);
6039 }
6040 
6041 // ---------------------------------------------------------------------------
6042 
6043 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6044 {
6045 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6046  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6047  AnsiString(VLoc));
6048 // find topmost LC, opening them all (to trains) in turn
6049  int UpStep = 0;
6050 
6051  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6052  {
6053  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6054  UpStep--;
6055  }
6056 // now find bottommost LC, opening them all (to trains) in turn
6057  int DownStep = 1;
6058 
6059  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6060  {
6061  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6062  DownStep++;
6063  }
6064 // find leftmost LC, opening them all (to trains) in turn
6065  int LeftStep = 0;
6066 
6067  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6068  {
6069  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6070  LeftStep--;
6071  }
6072 // now find rightmost LC, opening them all (to trains) in turn
6073  int RightStep = 1;
6074 
6075  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6076  {
6077  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6078  RightStep++;
6079  }
6080  Utilities->CallLogPop(1915);
6081 }
6082 
6083 // ---------------------------------------------------------------------------
6084 
6085 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6086 {
6087  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6088 // work upwards setting all to manual
6089  int UpStep = -1;
6090 
6091  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6092  {
6093  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6094  UpStep--;
6095  }
6096 // work downwards setting all to manual
6097  int DownStep = 1;
6098 
6099  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6100  {
6101  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6102  DownStep++;
6103  }
6104 // work leftwards setting all to manual
6105  int LeftStep = -1;
6106 
6107  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6108  {
6109  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6110  LeftStep--;
6111  }
6112 // work rightwards setting all to manual
6113  int RightStep = 1;
6114 
6115  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6116  {
6117  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6118  RightStep++;
6119  }
6120  Utilities->CallLogPop(2242);
6121 }
6122 
6123 // ---------------------------------------------------------------------------
6124 
6125 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6126 {
6127  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6128  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6129  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6130  {
6131  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6132  {
6133  BarriersDownVector.at(x).TypeOfRoute = 2;
6134  break;
6135  }
6136  }
6137  Utilities->CallLogPop(2243);
6138 }
6139 
6140 // ---------------------------------------------------------------------------
6141 
6142 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6143 {
6144  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6145 // work upwards
6146  int UpStep = 0; //start with this location
6147 
6148  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6149  {
6150  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6151  {
6152  Utilities->CallLogPop(2244);
6153  return(true);
6154  }
6155  UpStep--;
6156  }
6157 // work downwards
6158  int DownStep = 1;
6159 
6160  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6161  {
6162  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6163  {
6164  Utilities->CallLogPop(2245);
6165  return(true);
6166  }
6167  DownStep++;
6168  }
6169 // work leftwards
6170  int LeftStep = -1;
6171 
6172  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6173  {
6174  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6175  {
6176  Utilities->CallLogPop(2246);
6177  return(true);
6178  }
6179  LeftStep--;
6180  }
6181 // work rightwards
6182  int RightStep = 1;
6183 
6184  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6185  {
6186  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6187  {
6188  Utilities->CallLogPop(2247);
6189  return(true);
6190  }
6191  RightStep++;
6192  }
6193  Utilities->CallLogPop(2248);
6194  return(false);
6195 }
6196 
6197 // ---------------------------------------------------------------------------
6198 
6199 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6200 {
6201  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6202  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6203  {
6204  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6205  {
6206  BDVectorPos = x;
6207  Utilities->CallLogPop(2249);
6208  return(true);
6209  }
6210  }
6211  BDVectorPos = -1;
6212  Utilities->CallLogPop(2250);
6213  return(false);
6214 }
6215 
6216 // ---------------------------------------------------------------------------
6217 
6218 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6219 // open to trains
6220 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6221 {
6222  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6223  AnsiString(VLoc));
6224  if(!IsLCAtHV(4, HLoc, VLoc))
6225  {
6226  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6227  }
6228  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6229  {
6230  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6231  }
6232 // check for adjacent LCs & if so open (to trains)
6233  if(BaseElementSpeedTag == 1) // hor track element
6234  {
6235  // find topmost LC, opening them all (to trains) in turn
6236  int UpStep = 0;
6237  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6238  {
6239  UpStep--;
6240  }
6241  UpStep++;
6242  // now find bottommost LC, opening them all (to trains) in turn
6243  int DownStep = 1;
6244  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6245  {
6246  DownStep++;
6247  }
6248  DownStep--;
6249  // now plot graphics, UpStep is smallest & DownStep largest
6250  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6251  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6252  Graphics::TBitmap *RouteGraphic;
6253  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6254  if(TypeOfRoute == 1)
6255  {
6256  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6257  }
6258  else if(TypeOfRoute == 0)
6259  {
6260  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6261  }
6262  else //manual - no route
6263  {
6264  RouteGraphic = BaseGraphic;
6265  }
6266 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6267 // LinkSigRouteGraphicsPtr[1] ver }
6268 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6269 // LinkNonSigRouteGraphicsPtr[1] ver }
6270 
6271  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6272  {
6273  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6274  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6275  if(!Manual)
6276  {
6277  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6278  }
6279  else
6280  {
6281  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6282  }
6283  }
6284  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6285  {
6286  if(UpStep == 0)
6287  {
6288  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6289  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6290  if(!Manual)
6291  {
6292  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6293  }
6294  else
6295  {
6296  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6297  }
6298  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6299  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6300  if(!Manual)
6301  {
6302  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6303  }
6304  else
6305  {
6306  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6307  }
6308  }
6309  else
6310  {
6311  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6312  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6313  if(!Manual)
6314  {
6315  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6316  }
6317  else
6318  {
6319  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6320  }
6321  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6322  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6323  if(!Manual)
6324  {
6325  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6326  }
6327  else
6328  {
6329  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6330  }
6331  }
6332  }
6333  else // at least one plain graphic
6334  {
6335  if(UpStep == 0)
6336  {
6337  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6338  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6339  if(!Manual)
6340  {
6341  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6342  }
6343  else
6344  {
6345  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6346  }
6347  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6348  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6349  if(!Manual)
6350  {
6351  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6352  }
6353  else
6354  {
6355  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6356  }
6357  }
6358  else if(DownStep == 0)
6359  {
6360  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6361  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6362  if(!Manual)
6363  {
6364  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6365  }
6366  else
6367  {
6368  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6369  }
6370  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6371  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6372  if(!Manual)
6373  {
6374  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6375  }
6376  else
6377  {
6378  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6379  }
6380  }
6381  else
6382  {
6383  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6384  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6385  if(!Manual)
6386  {
6387  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6388  }
6389  else
6390  {
6391  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6392  }
6393  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6394  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6395  if(!Manual)
6396  {
6397  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6398  }
6399  else
6400  {
6401  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6402  }
6403  }
6404  for(int x = (UpStep + 1); x < DownStep; x++)
6405  {
6406  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6407  if(x == 0)
6408  {
6409  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6410  }
6411  else
6412  {
6413  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6414  }
6415  if(!Manual)
6416  {
6417  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6418  }
6419  else
6420  {
6421  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6422  }
6423  }
6424  }
6425  Disp->Update();
6426  Utilities->CallLogPop(1958);
6427  return;
6428  }
6429 
6430  else // ver track element
6431  {
6432  // find leftmost LC, opening them all (to trains) in turn
6433  int LStep = 0;
6434  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6435  {
6436  LStep--;
6437  }
6438  LStep++;
6439  // now find rightmost LC, opening them all (to trains) in turn
6440  int RStep = 1;
6441  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6442  {
6443  RStep++;
6444  }
6445  RStep--;
6446  // now plot graphics, LStep is smallest & RStep largest
6447  Graphics::TBitmap *RouteGraphic;
6448  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6449  if(TypeOfRoute == 1)
6450  {
6451  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6452  }
6453  else if(TypeOfRoute == 0)
6454  {
6455  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6456  }
6457  else //manual
6458  {
6459  RouteGraphic = BaseGraphic;
6460  }
6461 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6462 // LinkSigRouteGraphicsPtr[1] ver }
6463 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6464 // LinkNonSigRouteGraphicsPtr[1] ver }
6465  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6466  {
6467  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6468  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6469  if(!Manual)
6470  {
6471  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6472  }
6473  else
6474  {
6475  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6476  }
6477  }
6478  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6479  {
6480  if(LStep == 0)
6481  {
6482  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6483  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6484  if(!Manual)
6485  {
6486  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6487  }
6488  else
6489  {
6490  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6491  }
6492  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6493  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6494  if(!Manual)
6495  {
6496  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6497  }
6498  else
6499  {
6500  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6501  }
6502  }
6503  else
6504  {
6505  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6506  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6507  if(!Manual)
6508  {
6509  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6510  }
6511  else
6512  {
6513  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6514  }
6515  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6516  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6517  if(!Manual)
6518  {
6519  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6520  }
6521  else
6522  {
6523  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6524  }
6525  }
6526  }
6527  else // at least one plain graphic
6528  {
6529  if(LStep == 0)
6530  {
6531  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6532  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6533  if(!Manual)
6534  {
6535  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6536  }
6537  else
6538  {
6539  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6540  }
6541  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6542  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6543  if(!Manual)
6544  {
6545  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6546  }
6547  else
6548  {
6549  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6550  }
6551  }
6552  else if(RStep == 0)
6553  {
6554  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6555  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6556  if(!Manual)
6557  {
6558  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6559  }
6560  else
6561  {
6562  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6563  }
6564  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6565  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6566  if(!Manual)
6567  {
6568  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6569  }
6570  else
6571  {
6572  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6573  }
6574  }
6575  else
6576  {
6577  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6578  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6579  if(!Manual)
6580  {
6581  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6582  }
6583  else
6584  {
6585  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6586  }
6587  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6588  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6589  if(!Manual)
6590  {
6591  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6592  }
6593  else
6594  {
6595  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6596  }
6597  }
6598  for(int x = (LStep + 1); x < RStep; x++)
6599  {
6600  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6601  if(x == 0)
6602  {
6603  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6604  }
6605  else
6606  {
6607  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6608  }
6609  if(!Manual)
6610  {
6611  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6612  }
6613  else
6614  {
6615  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6616  }
6617  }
6618  }
6619  Disp->Update();
6620  Utilities->CallLogPop(1896);
6621  return;
6622  }
6623 }
6624 
6625 // ---------------------------------------------------------------------------
6626 
6627 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6628 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6629 {
6630  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6631  AnsiString(HLoc) + "," + AnsiString(VLoc));
6632  if(!IsLCAtHV(29, HLoc, VLoc))
6633  {
6634  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6635  }
6636  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6637  {
6638  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6639  }
6640 // check for adjacent LCs & if so open (to trains)
6641  if(BaseElementSpeedTag == 1) // hor track element
6642  {
6643  // find topmost LC, opening them all (to trains) in turn
6644  int UpStep = 0;
6645  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6646  {
6647  UpStep--;
6648  }
6649  UpStep++;
6650  // now find bottommost LC, opening them all (to trains) in turn
6651  int DownStep = 1;
6652  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6653  {
6654  DownStep++;
6655  }
6656  DownStep--;
6657  // now plot graphics, UpStep is smallest & DownStep largest
6658  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6659  {
6660  if(!Manual)
6661  {
6662  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6663  }
6664  else
6665  {
6666  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6667  }
6668  }
6669  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6670  {
6671  if(!Manual)
6672  {
6673  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6674  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6675  }
6676  else
6677  {
6678  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6679  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6680  }
6681  }
6682  else // at least one plain graphic
6683  {
6684  if(!Manual)
6685  {
6686  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6687  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6688  for(int x = (UpStep + 1); x < DownStep; x++)
6689  {
6690  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6691  }
6692  }
6693  else
6694  {
6695  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6696  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6697  for(int x = (UpStep + 1); x < DownStep; x++)
6698  {
6699  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6700  }
6701  }
6702  }
6703  // set markers
6704  for(int x = UpStep; x <= DownStep; x++)
6705  {
6706  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6707  }
6708  Display->Update();
6709  Utilities->CallLogPop(1944);
6710  return;
6711  }
6712 
6713  else // ver track element
6714  {
6715  // find leftmost LC, opening them all (to trains) in turn
6716  int LStep = 0;
6717  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6718  {
6719  LStep--;
6720  }
6721  LStep++;
6722  // now find rightmost LC, opening them all (to trains) in turn
6723  int RStep = 1;
6724  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6725  {
6726  RStep++;
6727  }
6728  RStep--;
6729  // now plot graphics, LStep is smallest & RStep largest
6730  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6731  {
6732  if(!Manual)
6733  {
6734  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6735  }
6736  else
6737  {
6738  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6739  }
6740  }
6741  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6742  {
6743  if(!Manual)
6744  {
6745  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6746  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6747  }
6748  else
6749  {
6750  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6751  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6752  }
6753  }
6754  else // at least one plain graphic
6755  {
6756  if(!Manual)
6757  {
6758  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6759  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6760  for(int x = (LStep + 1); x < RStep; x++)
6761  {
6762  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6763  }
6764  }
6765  else
6766  {
6767  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6768  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6769  for(int x = (LStep + 1); x < RStep; x++)
6770  {
6771  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6772  }
6773  }
6774  }
6775  // set markers
6776  for(int x = LStep; x <= RStep; x++)
6777  {
6778  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6779  }
6780  Disp->Update();
6781  Utilities->CallLogPop(1945);
6782  return;
6783  }
6784 }
6785 
6786 // ---------------------------------------------------------------------------
6787 
6788 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6789 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6790 {
6791  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6792  AnsiString(VLoc));
6793  if(!IsLCAtHV(9, HLoc, VLoc))
6794  {
6795  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6796  }
6797  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6798  {
6799  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6800  }
6801 // check for adjacent LCs & if so close (to trains)
6802  if(BaseElementSpeedTag == 1) // hor track element
6803  {
6804  // find topmost LC, closing them all (to trains) in turn
6805  int UpStep = 0;
6806  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6807  {
6808  UpStep--;
6809  }
6810  UpStep++;
6811  // now find bottommost LC, opening them all (to trains) in turn
6812  int DownStep = 1;
6813  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6814  {
6815  DownStep++;
6816  }
6817  DownStep--;
6818  // now plot graphics, UpStep is smallest & DownStep largest
6819  for(int x = UpStep; x < (DownStep + 1); x++)
6820  {
6821  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6822  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6823  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6824  }
6825  Disp->Update();
6826  Utilities->CallLogPop(1959);
6827  return;
6828  }
6829 
6830  else // ver track element
6831  {
6832  // find leftmost LC, closing them all (to trains) in turn
6833  int LStep = 0;
6834  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6835  {
6836  LStep--;
6837  }
6838  LStep++;
6839  // now find rightmost LC, opening them all (to trains) in turn
6840  int RStep = 1;
6841  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6842  {
6843  RStep++;
6844  }
6845  RStep--;
6846  // now plot graphics, LStep is smallest & RStep largest
6847  for(int x = LStep; x < (RStep + 1); x++)
6848  {
6849  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6850  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6851  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6852  }
6853  Disp->Update();
6854  Utilities->CallLogPop(1960);
6855  return;
6856  }
6857 }
6858 
6859 // ---------------------------------------------------------------------------
6860 
6861 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6862 // closed to trains
6863 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6864 {
6865  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6866  AnsiString(HLoc) + "," + AnsiString(VLoc));
6867  if(!IsLCAtHV(34, HLoc, VLoc))
6868  {
6869  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6870  }
6871  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6872  {
6873  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6874  }
6875  TTrackElement TE;
6876 
6877 // check for adjacent LCs & if so close (to trains)
6878  if(BaseElementSpeedTag == 1) // hor track element
6879  {
6880  // find topmost LC, closing them all (to trains) in turn
6881  int UpStep = 0;
6882  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6883  {
6884  UpStep--;
6885  }
6886  UpStep++;
6887  // now find bottommost LC, opening them all (to trains) in turn
6888  int DownStep = 1;
6889  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6890  {
6891  DownStep++;
6892  }
6893  DownStep--;
6894  // now plot graphics, UpStep is smallest & DownStep largest
6895  for(int x = UpStep; x <= DownStep; x++)
6896  {
6897  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6898  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6899  }
6900  Display->Update();
6901  Utilities->CallLogPop(1946);
6902  return;
6903  }
6904 
6905  else // ver track element
6906  {
6907  // find leftmost LC, closing them all (to trains) in turn
6908  int LStep = 0;
6909  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
6910  {
6911  LStep--;
6912  }
6913  LStep++;
6914  // now find rightmost LC, opening them all (to trains) in turn
6915  int RStep = 1;
6916  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
6917  {
6918  RStep++;
6919  }
6920  RStep--;
6921  // now plot graphics, LStep is smallest & RStep largest
6922  for(int x = LStep; x <= RStep; x++)
6923  {
6924  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6925  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
6926  }
6927  Display->Update();
6928  Utilities->CallLogPop(1947);
6929  return;
6930  }
6931 }
6932 
6933 // ---------------------------------------------------------------------------
6934 
6935 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
6936 {
6937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6938  Graphics::TBitmap *RouteGraphic;
6939  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6940 
6941  if(BaseElementSpeedTag == 1)
6942  {
6943  if(TypeOfRoute == 1)
6944  {
6945  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6946  }
6947  else if(TypeOfRoute == 0)
6948  {
6949  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6950  }
6951  else //manual
6952  {
6953  RouteGraphic = BaseGraphic;
6954  }
6955  if(State == Raising)
6956  {
6957  RouteGraphic = BaseGraphic;
6958  }
6959  }
6960  else
6961  {
6962  BaseGraphic = RailGraphics->gl2;
6963  if(TypeOfRoute == 1)
6964  {
6965  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6966  }
6967  else if(TypeOfRoute == 0)
6968  {
6969  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6970  }
6971  else
6972  {
6973  RouteGraphic = BaseGraphic; //manual
6974  }
6975  if(State == Raising)
6976  {
6977  RouteGraphic = BaseGraphic;
6978  }
6979  }
6980  int UpStep = 0;
6981 
6982  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6983  {
6984  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6985  if(UpStep == 0)
6986  {
6987  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6988  }
6989  else
6990  {
6991  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6992  }
6993  UpStep--;
6994  }
6995 // now find bottommost LC, opening them all (to trains) in turn
6996  int DownStep = 1;
6997 
6998  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
6999  {
7000  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7001  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7002  DownStep++;
7003  }
7004  int LeftStep = 0;
7005 
7006  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7007  {
7008  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7009  if(LeftStep == 0)
7010  {
7011  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7012  }
7013  else
7014  {
7015  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7016  }
7017  LeftStep--;
7018  }
7019 // now find rightmost LC, opening them all (to trains) in turn
7020  int RightStep = 1;
7021 
7022  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7023  {
7024  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7025  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7026  RightStep++;
7027  }
7028  Disp->Update();
7029  Utilities->CallLogPop(1914);
7030 }
7031 
7032 // ---------------------------------------------------------------------------
7033 
7034 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7035 {
7036 // return false for no LC there, flashing or a closed (to trains) LC
7037  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7038  bool FoundFlag;
7039  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7040 
7041  if(!FoundFlag)
7042  {
7043  Utilities->CallLogPop(1898);
7044  return(false);
7045  }
7046  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7047  {
7048  Utilities->CallLogPop(1899);
7049  return(false);
7050  }
7051  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7052  {
7053  Utilities->CallLogPop(1900);
7054  return(true);
7055  }
7056  Utilities->CallLogPop(1901);
7057  return(false);
7058 }
7059 
7060 // ---------------------------------------------------------------------------
7061 
7062 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7063 {
7064 // return false for no LC there, flashing LC or open (to trains) LC
7065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7066  bool FoundFlag;
7067  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7068 
7069  if(!FoundFlag)
7070  {
7071  Utilities->CallLogPop(1922);
7072  return(false);
7073  }
7074  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7075  {
7076  Utilities->CallLogPop(1923);
7077  return(false);
7078  }
7079  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7080  {
7081  Utilities->CallLogPop(1924);
7082  return(true);
7083  }
7084  Utilities->CallLogPop(1925);
7085  return(false);
7086 }
7087 
7088 // ---------------------------------------------------------------------------
7089 
7090 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7091 {
7092 // return true for barrier in process of moving
7093  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7094  bool FoundFlag;
7095  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7096 
7097  if(!FoundFlag)
7098  {
7099  Utilities->CallLogPop(1918);
7100  return(false);
7101  }
7102  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7103  {
7104  Utilities->CallLogPop(1919);
7105  return(false);
7106  }
7107  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7108  {
7109  Utilities->CallLogPop(1920);
7110  return(true);
7111  }
7112  Utilities->CallLogPop(1921);
7113  return(false);
7114 }
7115 
7116 // ---------------------------------------------------------------------------
7117 
7118 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7119 {
7120 // return true for an LC at H&V
7121  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7122  bool FoundFlag;
7123  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7124 
7125  if(!FoundFlag)
7126  {
7127  Utilities->CallLogPop(1902);
7128  return(false);
7129  }
7130  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7131  {
7132  Utilities->CallLogPop(1903);
7133  return(false);
7134  }
7135  Utilities->CallLogPop(1904);
7136  return(true);
7137 }
7138 
7139 // ---------------------------------------------------------------------------
7140 
7141 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7142 {
7143  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7144  AnsiString(Attr));
7145  bool FoundFlag;
7146  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7147 
7148  if(!FoundFlag)
7149  {
7150  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7151  }
7152  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7153  {
7154  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7155  }
7156  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7157  Utilities->CallLogPop(1905);
7158  return;
7159 }
7160 
7161 // ---------------------------------------------------------------------------
7162 
7164 {
7165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7166  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7167  {
7168  TTrackElement InactiveTrackElement = InactiveTrackVector.at(x);
7169  if(InactiveTrackElement.TrackType == LevelCrossing)
7170  {
7171  InactiveTrackVector.at(x).Attribute = 0;
7172  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7173  }
7174  }
7175  Utilities->CallLogPop(1913);
7176  return;
7177 }
7178 
7179 // ---------------------------------------------------------------------------
7180 
7181 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7182 {
7183 // return true if there is either a route set or being set on any element or a train on any element
7184  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7185  "," + AnsiString(VLoc));
7186 
7187  THVPair TrackMapKeyPair;
7188  TTrack::TTrackMapIterator TrackMapPtr;
7189  int DummyRouteNumber;
7190 
7191  TrainPresent = false;
7192 // find topmost LC, checking each for routes & trains
7193  int UpStep = 0;
7194 
7195  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7196  {
7197  TrackMapKeyPair.first = HLoc;
7198  TrackMapKeyPair.second = VLoc + UpStep;
7199  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7200  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7201  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7202  {
7203  Utilities->CallLogPop(1932);
7204  return(true);
7205  }
7206  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7207  {
7208  TrainPresent = true;
7209  Utilities->CallLogPop(1933);
7210  return(true);
7211  }
7212  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7213  {
7214  Utilities->CallLogPop(2274);
7215  return(true);
7216  }
7217  UpStep--;
7218  }
7219 // now find bottommost LC, opening them all (to trains) in turn
7220  int DownStep = 1;
7221 
7222  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7223  {
7224  TrackMapKeyPair.first = HLoc;
7225  TrackMapKeyPair.second = VLoc + DownStep;
7226  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7227  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7228  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7229  {
7230  Utilities->CallLogPop(1934);
7231  return(true);
7232  }
7233  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7234  {
7235  TrainPresent = true;
7236  Utilities->CallLogPop(1935);
7237  return(true);
7238  }
7239  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7240  {
7241  Utilities->CallLogPop(2275);
7242  return(true);
7243  }
7244  DownStep++;
7245  }
7246 // find leftmost LC
7247  int LeftStep = 0;
7248 
7249  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7250  {
7251  TrackMapKeyPair.first = HLoc + LeftStep;
7252  TrackMapKeyPair.second = VLoc;
7253  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7254  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7255  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7256  {
7257  Utilities->CallLogPop(1936);
7258  return(true);
7259  }
7260  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7261  {
7262  TrainPresent = true;
7263  Utilities->CallLogPop(1937);
7264  return(true);
7265  }
7266  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7267  {
7268  Utilities->CallLogPop(2276);
7269  return(true);
7270  }
7271  LeftStep--;
7272  }
7273 // now find rightmost LC, opening them all (to trains) in turn
7274  int RightStep = 1;
7275 
7276  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7277  {
7278  TrackMapKeyPair.first = HLoc + RightStep;
7279  TrackMapKeyPair.second = VLoc;
7280  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7281  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7282  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7283  {
7284  Utilities->CallLogPop(1938);
7285  return(true);
7286  }
7287  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7288  {
7289  TrainPresent = true;
7290  Utilities->CallLogPop(1939);
7291  return(true);
7292  }
7293  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7294  {
7295  Utilities->CallLogPop(2277);
7296  return(true);
7297  }
7298  RightStep++;
7299  }
7300  Utilities->CallLogPop(1940);
7301  return(false);
7302 }
7303 
7304 // ---------------------------------------------------------------------------
7305 
7306 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7307 {
7308  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7309  for(unsigned int x = 0; x < SearchVector.size(); x++)
7310  {
7311  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7312  {
7313  Utilities->CallLogPop(2278);
7314  return true;
7315  }
7316  }
7317  Utilities->CallLogPop(2279);
7318  return false;
7319 }
7320 
7321 // ---------------------------------------------------------------------------
7322 
7323 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7324 {
7325  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7326  if(TrackElement.TrackType != Points)
7327  {
7328  throw Exception("Error, Wrong track type in GetFilletGraphic");
7329  }
7330  if(TrackElement.SpeedTag < 28)
7331  {
7332  Utilities->CallLogPop(521);
7333  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7334  }
7335  else if(TrackElement.SpeedTag < 132)
7336  {
7337  Utilities->CallLogPop(522);
7338 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7339  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7340  }
7341  else
7342  {
7343  Utilities->CallLogPop(1537);
7344  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7345  }
7346 }
7347 
7348 // ---------------------------------------------------------------------------
7349 
7351 {
7352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7353  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7354  {
7355  TrackVector.at(x).TrainIDOnElement = -1;
7356  TrackVector.at(x).TrainIDOnBridgeTrackPos01 = -1;
7357  TrackVector.at(x).TrainIDOnBridgeTrackPos23 = -1;
7358  }
7359  Utilities->CallLogPop(1342);
7360 }
7361 
7362 // ---------------------------------------------------------------------------
7363 
7364 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7365 /*
7366  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7367 */
7368 {
7369  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7370  AnsiString(ScreenPosV));
7371  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7372  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7373 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7374  Utilities->CallLogPop(535);
7375 }
7376 
7377 // ---------------------------------------------------------------------------
7378 
7379 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7380 /*
7381  Converts the screen position to the true (without offsets) position
7382 */
7383 {
7384  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7385  AnsiString(ScreenPosV));
7386  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7387  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7388  Utilities->CallLogPop(536);
7389 }
7390 
7391 // ---------------------------------------------------------------------------
7392 
7393 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7394 {
7395  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7396  AnsiString(VPosTrue));
7397  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7398  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7399  Utilities->CallLogPop(537);
7400 }
7401 
7402 // ---------------------------------------------------------------------------
7403 
7404 void TTrack::CheckMapAndTrack(int Caller) // test
7405 {
7406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7407  int Zeroes = 0;
7408  bool FoundFlag;
7409 
7410  for(unsigned int a = 0; a < TrackVector.size(); a++)
7411  {
7412  TTrackElement CheckElement = Track->TrackVector.at(a);
7413  if(CheckElement.SpeedTag == 0)
7414  {
7415  Zeroes++; // zeroed elements not saved in map
7416  }
7417  else
7418  {
7419  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7420  if(!FoundFlag)
7421  {
7422  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7423  " in TrackMap, Caller=" + (AnsiString)Caller);
7424  }
7425  if(MapVecPos != (int)a)
7426  {
7427  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7428  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7429  (AnsiString)Caller);
7430  }
7431  }
7432  }
7433  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7434  {
7435  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7436  " Caller=" + (AnsiString)Caller);
7437  }
7438  Utilities->CallLogPop(538);
7439  return;
7440 }
7441 
7442 // ---------------------------------------------------------------------------
7443 
7444 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7445 {
7446  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7447  bool FoundFlag;
7448  TIMPair InactivePair;
7449 
7450  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7451  {
7452  TTrackElement CheckElement = Track->InactiveTrackVector.at(a);
7453  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7454  if(!FoundFlag)
7455  {
7456  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7457  " in InactiveMap, Caller=" + (AnsiString)Caller);
7458  }
7459  if((InactivePair.first != a) && (InactivePair.second != a))
7460  {
7461  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7462  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7463  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7464  }
7465  }
7466  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7467  {
7468  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7469  " Caller=" + (AnsiString)Caller);
7470  }
7471  Utilities->CallLogPop(539);
7472 }
7473 
7474 // ---------------------------------------------------------------------------
7475 
7476 void TTrack::CheckGapMap(int Caller) // test
7477 {
7478  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7479  int Position1, Position2;
7480  TTrackElement TrackElement1, TrackElement2;
7481  TGapMapIterator GapMapPtr;
7482 
7483  if(!GapMap.empty())
7484  {
7485  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7486  {
7487  int HLoc1 = GapMapPtr->first.first;
7488  int VLoc1 = GapMapPtr->first.second;
7489  int HLoc2 = GapMapPtr->second.first;
7490  int VLoc2 = GapMapPtr->second.second;
7491  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7492  {
7493  throw Exception("Failed to find H & V for gap1, GapMap in error");
7494  }
7495  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7496  {
7497  throw Exception("Failed to find H & V for gap2, GapMap in error");
7498  }
7499  if(TrackElementAt(17, Position1).TrackType != GapJump)
7500  {
7501  throw Exception("Element at Pos1 not a gap, GapMap in error");
7502  }
7503  if(TrackElementAt(18, Position2).TrackType != GapJump)
7504  {
7505  throw Exception("Element at Pos2 not a gap, GapMap in error");
7506  }
7507  }
7508  }
7509  unsigned int GapCount = 0;
7510 
7511  for(unsigned int a = 0; a < TrackVector.size(); a++)
7512  {
7513  TTrackElement CheckElement = Track->TrackVector.at(a);
7514  if(CheckElement.TrackType == GapJump)
7515  {
7516  GapCount++;
7517  }
7518  }
7519  if((GapMap.size() * 2) != GapCount)
7520  {
7521  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7522  (AnsiString)Caller);
7523  }
7524  Utilities->CallLogPop(540);
7525 }
7526 
7527 // ---------------------------------------------------------------------------
7528 
7529 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7530 {
7531  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7532  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7533  {
7534  if(TrackFinished)
7535  {
7536  throw Exception("Error - TrackFinished with erase element still present");
7537  }
7538  Utilities->CallLogPop(541);
7539  return; // erased element, can't set ID
7540  }
7541  AnsiString IDString;
7542 
7543  if(TrackElement.HLoc < 0)
7544  {
7545  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7546  }
7547  else
7548  {
7549  IDString = AnsiString(TrackElement.HLoc) + "-";
7550  }
7551  if(TrackElement.VLoc < 0)
7552  {
7553  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7554  }
7555  else
7556  {
7557  IDString += AnsiString(TrackElement.VLoc);
7558  }
7559  TrackElement.ElementID = IDString;
7560  Utilities->CallLogPop(542);
7561 }
7562 
7563 // ---------------------------------------------------------------------------
7564 
7565 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7566 {
7567 // e.g. "8-13", "00008-13", "N43-N127", etc
7568  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7569  int DelimPos;
7570 
7571  for(int x = 1; x < String.Length() + 1; x++)
7572  {
7573  if(String.IsDelimiter("-", x))
7574  {
7575  DelimPos = x;
7576  break;
7577  }
7578  if(x == String.Length())
7579  {
7580  if(GiveMessages)
7581  {
7582  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7583  }
7584  Utilities->CallLogPop(543);
7585  return(-1);
7586  }
7587  }
7588  if(DelimPos == 1)
7589  {
7590  if(GiveMessages)
7591  {
7592  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7593  }
7594  Utilities->CallLogPop(544);
7595  return(-1);
7596  }
7597  if(DelimPos == String.Length())
7598  {
7599  if(GiveMessages)
7600  {
7601  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7602  }
7603  Utilities->CallLogPop(545);
7604  return(-1);
7605  }
7606  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7607  {
7608  if(GiveMessages)
7609  {
7610  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7611  }
7612  Utilities->CallLogPop(1508);
7613  return(-1);
7614  }
7615  int HLoc, VLoc;
7616 
7617  if(String.SubString(1, 1) != "N")
7618  {
7619  for(int x = 1; x < DelimPos; x++)
7620  {
7621  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7622  {
7623  if(GiveMessages)
7624  {
7625  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7626  }
7627  Utilities->CallLogPop(546);
7628  return(-1);
7629  }
7630  }
7631  }
7632  if(String.SubString(1, 1) == "N")
7633  {
7634  for(int x = 2; x < DelimPos; x++)
7635  {
7636  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7637  {
7638  if(GiveMessages)
7639  {
7640  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7641  }
7642  Utilities->CallLogPop(763);
7643  return(-1);
7644  }
7645  }
7646  }
7647  if(String.SubString(1, 1) == "N")
7648  {
7649  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7650  }
7651  else
7652  {
7653  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7654  }
7655  if(String.SubString(DelimPos + 1, 1) != "N")
7656  {
7657  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7658  {
7659  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7660  {
7661  if(GiveMessages)
7662  {
7663  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7664  }
7665  Utilities->CallLogPop(547);
7666  return(-1);
7667  }
7668  }
7669  }
7670  if(String.SubString(DelimPos + 1, 1) == "N")
7671  {
7672  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7673  {
7674  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7675  {
7676  if(GiveMessages)
7677  {
7678  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7679  }
7680  Utilities->CallLogPop(764);
7681  return(-1);
7682  }
7683  }
7684  }
7685  if(String.SubString(DelimPos + 1, 1) == "N")
7686  {
7687  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7688  }
7689  else
7690  {
7691  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7692  }
7693  THVPair HVPair(HLoc, VLoc);
7694  TTrackMapIterator TrackMapPtr;
7695 
7696  TrackMapPtr = TrackMap.find(HVPair);
7697  if(TrackMapPtr == TrackMap.end())
7698  {
7699  if(GiveMessages)
7700  {
7701  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7702  }
7703  Utilities->CallLogPop(548);
7704  return(-1);
7705  }
7706  Utilities->CallLogPop(549);
7707  return(TrackMapPtr->second);
7708 }
7709 
7710 // ---------------------------------------------------------------------------
7711 
7712 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7713 /*
7714  True for linked properly at both ends
7715 */
7716 {
7717  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7718  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7719  int HLoc = TrackElement.HLoc;
7720  int VLoc = TrackElement.VLoc;
7721 
7722  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7723  {
7724  Utilities->CallLogPop(1821);
7725  return(false);
7726  }
7727  if(TrackElement.SpeedTag == 129) // vertical footbridge
7728  {
7729  // check top connection
7730  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7731  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7732  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7733  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7734  {
7735  Utilities->CallLogPop(550);
7736  return(false);
7737  }
7738  // check bottom connection
7739  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7740  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7741  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7742  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7743  {
7744  Utilities->CallLogPop(551);
7745  return(false);
7746  }
7747  }
7748  if(TrackElement.SpeedTag == 145) // vertical underpass
7749  {
7750  // check top connection
7751  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7752  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7753  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7754  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7755  {
7756  Utilities->CallLogPop(2114);
7757  return(false);
7758  }
7759  // check bottom connection
7760  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7761  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7762  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7763  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7764  {
7765  Utilities->CallLogPop(2115);
7766  return(false);
7767  }
7768  }
7769  if(TrackElement.SpeedTag == 130) // hor footbridge
7770  {
7771  // check left connection
7772  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7773  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7774  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7775  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7776  {
7777  Utilities->CallLogPop(552);
7778  return(false);
7779  }
7780  // check right connection
7781  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7782  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7783  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7784  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7785  {
7786  Utilities->CallLogPop(553);
7787  return(false);
7788  }
7789  }
7790  if(TrackElement.SpeedTag == 146) // hor u'pass
7791  {
7792  // check left connection
7793  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7794  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7795  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7796  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7797  {
7798  Utilities->CallLogPop(2116);
7799  return(false);
7800  }
7801  // check right connection
7802  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7803  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7804  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7805  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7806  {
7807  Utilities->CallLogPop(2117);
7808  return(false);
7809  }
7810  }
7811  Utilities->CallLogPop(554);
7812  return(true);
7813 }
7814 
7815 // ---------------------------------------------------------------------------
7816 
7817 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7818 /*
7819  return true if the SpeedTag present in the map at H & V
7820 */
7821 {
7822  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7823  AnsiString(SpeedTag));
7824  if(InactiveTrack2MultiMap.empty())
7825  {
7826  Utilities->CallLogPop(555);
7827  return(false);
7828  }
7829  THVPair HVPair(HLoc, VLoc);
7831  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7832  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7833 
7834  if(HVRange.first == HVRange.second)
7835  {
7836  Utilities->CallLogPop(556);
7837  return(false);
7838  }
7839  else
7840  {
7841  HVIt1 = HVRange.first;
7842  }
7843  TTrackElement Temp1, Temp2; // test
7844 
7845  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
7846  if(--HVRange.second != HVRange.first)
7847  {
7848  HVIt2 = HVRange.second;
7849  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
7850  }
7851  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
7852  HVIt2->second).SpeedTag == SpeedTag)))
7853  {
7854  Utilities->CallLogPop(557);
7855  return(true);
7856  }
7857  else
7858  {
7859  Utilities->CallLogPop(558);
7860  return(false);
7861  }
7862 }
7863 
7864 // ---------------------------------------------------------------------------
7865 
7866 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7867 /*
7868  return true if the SpeedTag present in the map at H & V
7869 */
7870 {
7871  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7872  AnsiString(SpeedTag));
7873  if(TrackMap.empty())
7874  {
7875  Utilities->CallLogPop(559);
7876  return(false);
7877  }
7878  THVPair HVPair(HLoc, VLoc);
7879  TTrackMapIterator End = TrackMap.end();
7880  TTrackMapIterator It = End;
7881 
7882  It = TrackMap.find(HVPair);
7883  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
7884  {
7885  Utilities->CallLogPop(560);
7886  return(true);
7887  }
7888  else
7889  {
7890  Utilities->CallLogPop(561);
7891  return(false);
7892  }
7893 }
7894 
7895 // ---------------------------------------------------------------------------
7896 
7897 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
7898 {
7899 /*
7900  General:
7901  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
7902  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
7903  a NamedNonStationLocation.
7904  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
7905  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
7906  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
7907  platform at that location).
7908 
7909  Linked named location elements are those explained in TTrack::TTrack()
7910 
7911  Detail:
7912  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
7913  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
7914  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
7915  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
7916  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
7917  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
7918 
7919  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
7920  this function a single element should be in the List (normally from the user's selection but can also be from
7921  SearchForAndUpdateLocationName), and the Map is cleared within the function.
7922  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
7923  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
7924  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
7925  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
7926  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
7927  moves them into the Map. At the end all linked elements are in the Map.
7928 
7929  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
7930  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
7931  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
7932 */
7933 
7934 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
7935 // Display->FileDiagnostics(TestString);//test
7936 
7937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
7938  AnsiString TestString1, TestString2; // test
7939 
7940  Track->LNDone2MultiMap.clear();
7941  if(LNPendingList.size() != 1)
7942  {
7943  throw Exception("LNPendingList size not 1 on entry");
7944  }
7945  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
7946  while(!LNPendingList.empty())
7947  {
7948  CurrentElementNumber = LNPendingList.front();
7949  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
7950  int NewElement; // = 2000000000; //marker for unused //not needed after v1.1.4
7951  int H = CurrentElement->HLoc;
7952  int V = CurrentElement->VLoc;
7953  int Tag = CurrentElement->SpeedTag;
7954  if(Tag == 76) // top plat
7955  {
7956  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
7957  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
7958  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
7959  for(int x = 0; x < 25; x++)
7960  {
7961  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
7962  {
7963  LNPendingList.insert(LNPendingList.end(), NewElement);
7964  }
7965  }
7966  }
7967  else if(Tag == 77) // bot plat
7968  {
7969  for(int x = 0; x < 25; x++)
7970  {
7971  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
7972  {
7973  LNPendingList.insert(LNPendingList.end(), NewElement);
7974  }
7975  }
7976  }
7977  else if(Tag == 78) // l plat
7978  {
7979  for(int x = 0; x < 25; x++)
7980  {
7981  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
7982  {
7983  LNPendingList.insert(LNPendingList.end(), NewElement);
7984  }
7985  }
7986  }
7987  else if(Tag == 79) // r plat
7988  {
7989  for(int x = 0; x < 25; x++)
7990  {
7991  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
7992  {
7993  LNPendingList.insert(LNPendingList.end(), NewElement);
7994  }
7995  }
7996  }
7997  else if(Tag == 96) // conc
7998  {
7999  for(int x = 0; x < 28; x++)
8000  {
8001  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8002  {
8003  LNPendingList.insert(LNPendingList.end(), NewElement);
8004  }
8005  }
8006  }
8007  else if(Tag == 129) // vert footbridge
8008  {
8009  for(int x = 0; x < 8; x++)
8010  {
8011  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8012  {
8013  LNPendingList.insert(LNPendingList.end(), NewElement);
8014  }
8015  }
8016  }
8017  else if(Tag == 130) // hor footbridge
8018  {
8019  for(int x = 0; x < 8; x++)
8020  {
8021  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8022  {
8023  LNPendingList.insert(LNPendingList.end(), NewElement);
8024  }
8025  }
8026  }
8027  else if(Tag == 131) // named location
8028  {
8029  for(int x = 0; x < 4; x++)
8030  {
8031  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8032  {
8033  LNPendingList.insert(LNPendingList.end(), NewElement);
8034  }
8035  }
8036  }
8037  else if(Tag == 145) // v u'pass
8038  {
8039  for(int x = 0; x < 8; x++)
8040  {
8041  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8042  {
8043  LNPendingList.insert(LNPendingList.end(), NewElement);
8044  }
8045  }
8046  }
8047  else if(Tag == 146) // h u'pass
8048  {
8049  for(int x = 0; x < 8; x++)
8050  {
8051  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8052  {
8053  LNPendingList.insert(LNPendingList.end(), NewElement);
8054  }
8055  }
8056  }
8057  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8058 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8059  if(AddingElements)
8060  {
8061  int HPos, VPos; // not used but needed for FindText function
8062  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8063  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8064  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8065  {
8066  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8067  if((ExistingName != "") && (ExistingName != LocationName))
8068  {
8069  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8070  {
8071  } // name not in LocationNameMultiMap, so don't erase from TextVector
8072  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8073  {
8074  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8075  {
8076  ;
8077  } // condition not used
8078 
8079  }
8080  }
8081  }
8082  }
8083  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8084  // track at that loc
8085  THVPair HVPair(H, V);
8086  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8087  LNDone2MultiMapEntry.first = HVPair;
8088  LNDone2MultiMapEntry.second = LNPendingList.front();
8089  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8090  LNPendingList.erase(LNPendingList.begin());
8091  }
8092 
8093 // search all name multimap for same name where corresponding active elements don't appear in
8094 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8095 
8096  TLocationNameMultiMapIterator SNIterator;
8097  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8098  bool FoundFlag, ErasedFlag = false;
8099 
8100  if(SNRange.first != SNRange.second)
8101  {
8102  SNRange.first--; // now pointing to before the first
8103  SNRange.second--; // now pointing to the last
8104  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8105  {
8106  // Same elements are in Done map as in name map
8107  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8108  {
8109  ErasedFlag = true;
8110  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8111  TVIt->LocationName = "";
8112  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8113  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8114  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8115  {
8116  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8117  if(FoundFlag)
8118  {
8119  TrackElementAt(20, Position).LocationName = "";
8120  TrackElementAt(21, Position).ActiveTrackElementName = "";
8121  }
8122  }
8123  // erase name in name map
8124 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8125  }
8126  }
8127  }
8128  if(ErasedFlag)
8129  {
8131  }
8132  if(TrackFinished)
8133  {
8135  }
8136 // set here as well as in LinkTrack so don't have to link track just because a name added
8137 // if track not finished then will be set when track validated
8138 
8139 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8140 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8141 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8142 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8143 // so the error would be seen.
8144 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8145  std::pair<AnsiString, char>TempMapPair;
8146 
8147  ContinuationNameMap.clear();
8148  for(int x = 0; x < Track->TrackVectorSize(); x++)
8149  {
8150  if((Track->TrackVector.at(x).TrackType == Continuation) && (Track->TrackVector.at(x).ActiveTrackElementName != ""))
8151  {
8152  TempMapPair.first = Track->TrackVector.at(x).ActiveTrackElementName;
8153  TempMapPair.second = 'x'; // unused
8154  ContinuationNameMap.insert(TempMapPair);
8155  }
8156  }
8157 //end of addition
8158  CheckLocationNameMultiMap(1); // test
8159  Utilities->CallLogPop(562);
8160 }
8161 
8162 // ---------------------------------------------------------------------------
8163 
8164 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8165 /*
8166  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8167  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8168 */
8169 {
8170  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8171  AnsiString(SpeedTag));
8172  if(!NamedLocationElementAt(2, HLoc, VLoc))
8173  {
8174  Utilities->CallLogPop(948);
8175  return(false);
8176  }
8177  bool FoundFlag;
8178  int Position = -1;
8179  TIMPair IMPair;
8180 
8181  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8182  {
8183  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8184  if(FoundFlag)
8185  {
8186  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8187  {
8188  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8189  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8190  // don't allow duplicates in either list, or processing takes a lot longer
8191  {
8192  FoundElement = MapPos;
8193  Utilities->CallLogPop(563);
8194  return(true);
8195  }
8196  }
8197  }
8198  }
8199  else
8200  {
8201  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8202  if(FoundFlag)
8203  {
8204  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8205  {
8206  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8207  {
8208  FoundElement = IMPair.first;
8209  Utilities->CallLogPop(564);
8210  return(true);
8211  }
8212  }
8213  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8214  {
8215  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8216  {
8217  FoundElement = IMPair.second;
8218  Utilities->CallLogPop(565);
8219  return(true);
8220  }
8221  }
8222  }
8223  }
8224  Utilities->CallLogPop(566);
8225  return(false);
8226 }
8227 
8228 // ---------------------------------------------------------------------------
8229 
8230 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8231 /*
8232  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8233  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8234  with the new name
8235 */
8236 {
8237  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8238  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8239 
8240  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8241  int HLoc = TrackElement->HLoc;
8242  int VLoc = TrackElement->VLoc;
8243  bool FoundFlag;
8244 
8245  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8246  // only have timetable names for adjacent platforms & named locations
8247  {
8248  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8249  if(FoundFlag)
8250  {
8251  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8252  }
8253  }
8254  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8255 
8256  if(ErrorString != "")
8257  {
8258  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8259  }
8260  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8261  CheckLocationNameMultiMap(2); // test
8262  Utilities->CallLogPop(567);
8263 }
8264 
8265 // ---------------------------------------------------------------------------
8266 
8267 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8268 /*
8269  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8270 */
8271 {
8272  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8273  if(LNDone2MultiMap.empty())
8274  {
8275  Utilities->CallLogPop(568);
8276  return(false);
8277  }
8278  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8279 
8280  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8281  {
8282  if(LNDone2MultiMapIterator->second == MapPos)
8283  {
8284  Utilities->CallLogPop(569);
8285  return(true);
8286  }
8287  }
8288  Utilities->CallLogPop(570);
8289  return(false);
8290 }
8291 
8292 // ---------------------------------------------------------------------------
8293 
8294 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8295 /*
8296  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8297 */
8298 {
8299  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8300  if(LNPendingList.empty())
8301  {
8302  Utilities->CallLogPop(571);
8303  return(false);
8304  }
8305  TLNPendingListIterator LNPendingListIterator;
8306 
8307  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8308  {
8309  if(*LNPendingListIterator == MapPos)
8310  {
8311  Utilities->CallLogPop(572);
8312  return(true);
8313  }
8314  }
8315  Utilities->CallLogPop(573);
8316  return(false);
8317 }
8318 
8319 // ---------------------------------------------------------------------------
8320 
8321 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8322 /*
8323  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8324 */
8325 {
8326  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8327  THVPair HVPair(HLoc, VLoc);
8328  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8329  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8330 
8331  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8332  {
8333  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8334  {
8335  Utilities->CallLogPop(574);
8336  return(true);
8337  }
8338  }
8339  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8340  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8341  {
8342  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8343  {
8344  Utilities->CallLogPop(575);
8345  return(true);
8346  }
8347  }
8348  Utilities->CallLogPop(576);
8349  return(false);
8350 }
8351 
8352 // ---------------------------------------------------------------------------
8353 
8354 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8355 {
8356  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8357  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8358  {
8359  Utilities->CallLogPop(1953);
8360  return(true);
8361  }
8362  Utilities->CallLogPop(1954);
8363  return(false);
8364 }
8365 
8366 // ---------------------------------------------------------------------------
8367 
8368 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8369 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8370 //program and used when try to save as a .rly file
8371 {
8372  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8375  if(LocationNameMultiMap.empty()) //no names so no duplicates
8376  {
8377  Utilities->CallLogPop(2254);
8378  return(false);
8379  }
8380  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8381  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8382  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8383  {
8385  {
8386  if(GiveMessage)
8387  {
8388  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8389  }
8390  Utilities->CallLogPop(2255);
8391  return(true);
8392  }
8393  }
8394  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8395  {
8396  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8397  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8398  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8399  {
8401  {
8402  if(GiveMessage)
8403  {
8404  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8405  }
8406  Utilities->CallLogPop(2256);
8407  return(true);
8408  }
8409  }
8410  }
8411  Utilities->CallLogPop(2257);
8412  return(false); //OK, no duplicates
8413 }
8414 
8415 // ---------------------------------------------------------------------------
8416 
8418 {
8419  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8420  THVPair HVPair;
8421  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8422  //for use in the duplicate check
8423  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8424  {
8425  if(LNMMIt->second < 0) //active track element
8426  {
8427  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8428  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8429  }
8430  else //inactive track element
8431  {
8432  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8433  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8434  }
8435  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8436  }
8437  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8438 
8439  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8440  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8441  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8442 
8443  std::list<THVPair> HVLinkedList;
8444 
8445  //set the first value to true and add it to the list
8446  HVPairsLinkedMap.begin()->second = true;
8447  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8448  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8449  //examination
8450  THVPair HVPairUnderExamination;
8451  THVPairsLinkedMap::iterator HVPLMIt;
8452  THVPair HVPairNew;
8453  while(!HVLinkedList.empty())
8454  {
8455  HVPairUnderExamination = HVLinkedList.front();
8456  HVLinkedList.pop_front();
8457  HVPairNew.first = HVPairUnderExamination.first;
8458  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8459  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8460  if(HVPLMIt != HVPairsLinkedMap.end())
8461  {
8462  if(!HVPLMIt->second)
8463  {
8464  HVLinkedList.push_back(HVPLMIt->first);
8465  }
8466  HVPLMIt->second = true;
8467  }
8468  HVPairNew.first = HVPairUnderExamination.first - 1;
8469  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8470  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8471  if(HVPLMIt != HVPairsLinkedMap.end())
8472  {
8473  if(!HVPLMIt->second)
8474  {
8475  HVLinkedList.push_back(HVPLMIt->first);
8476  }
8477  HVPLMIt->second = true;
8478  }
8479  HVPairNew.first = HVPairUnderExamination.first;
8480  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8481  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8482  if(HVPLMIt != HVPairsLinkedMap.end())
8483  {
8484  if(!HVPLMIt->second)
8485  {
8486  HVLinkedList.push_back(HVPLMIt->first);
8487  }
8488  HVPLMIt->second = true;
8489  }
8490  HVPairNew.first = HVPairUnderExamination.first + 1;
8491  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8492  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8493  if(HVPLMIt != HVPairsLinkedMap.end())
8494  {
8495  if(!HVPLMIt->second)
8496  {
8497  HVLinkedList.push_back(HVPLMIt->first);
8498  }
8499  HVPLMIt->second = true;
8500  }
8501  }
8502 
8503  //at the end if any have a false bool then the name is duplicated so return false
8504  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8505  {
8506  if(!HVPLMIt->second)
8507  {
8508  Utilities->CallLogPop(2258);
8509  return(false);
8510  }
8511  }
8512  Utilities->CallLogPop(2259);
8513  return(true);
8514 }
8515 
8516 // ---------------------------------------------------------------------------
8517 
8518 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8519 /*
8520  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8521 */
8522 
8523 {
8524  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8525  if(LocationName == "")
8526  {
8527  Utilities->CallLogPop(577);
8528  return(false);
8529  }
8530 // new for v0.2b
8531 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8533  {
8534  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8535  ActiveTrackElementNameMap.clear();
8536  for(unsigned int x = 0; x < TrackVector.size(); x++)
8537  {
8538  if((TrackVector.at(x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackVector.at(x).ActiveTrackElementName))
8539  == ContinuationNameMap.end())
8540  {
8541  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8542  ActiveTrackElementNameMapEntry.first = Track->TrackVector.at(x).ActiveTrackElementName;
8543  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8544  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8545  }
8546  }
8548  }
8549  Utilities->CallLogPop(578);
8550  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8551 // end of new section
8552 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8553 }
8554 
8555 // ---------------------------------------------------------------------------
8556 
8557 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8558 /*
8559  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8560  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8561  new names in the vectors.
8562 */
8563 {
8564  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8565  bool FoundFlag, ErasedFlag = false;
8566  TLocationNameMultiMapIterator SNIterator;
8567  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8568 
8569  if(SNRange.first != SNRange.second)
8570  {
8571  ErasedFlag = true;
8572  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8573  {
8574  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8575  TVIt->LocationName = "";
8576  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8577  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8578  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8579  {
8580  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8581  if(FoundFlag)
8582  {
8583  TrackElementAt(25, Position).LocationName = "";
8584  TrackElementAt(26, Position).ActiveTrackElementName = "";
8585  }
8586  }
8587  }
8588  }
8589  if(ErasedFlag)
8590  {
8592  }
8593  CheckLocationNameMultiMap(3); // test
8594  Utilities->CallLogPop(579);
8595 }
8596 
8597 // ---------------------------------------------------------------------------
8598 
8599 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8600 /*
8601  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8602  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8603  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8604  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8605  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8606  naming up to date with the deletion or insertion.
8607 */
8608 {
8609  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8610  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8611  LNPendingList.clear();
8612  AnsiString LocationName;
8613  int MapPos;
8614  bool FoundFlag = 0;
8615 
8616 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8617  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8618  if(FoundFlag)
8619  {
8620  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8621  if(LocationName != "")
8622  {
8623  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8624  EnterLocationName(13, LocationName, true);
8625  Utilities->CallLogPop(2251);
8626  return;
8627  }
8628  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8629  if(LocationName != "")
8630  {
8631  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8632  EnterLocationName(14, LocationName, true);
8633  Utilities->CallLogPop(2252);
8634  return;
8635  }
8636  }
8637 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8638 
8639  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8640  if(FoundFlag)
8641  {
8642  LocationName = TrackElementAt(1004, Position).LocationName;
8643  if(LocationName != "")
8644  {
8645  int ModifiedPosition = -1 - Position;
8646  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8647  EnterLocationName(15, LocationName, true);
8648  Utilities->CallLogPop(2253);
8649  return;
8650  }
8651  }
8652  if(SpeedTag == 76) // top plat
8653  {
8654  for(int x = 0; x < 25; x++)
8655  {
8656  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8657  {
8658  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8659  EnterLocationName(3, LocationName, true);
8660  break;
8661  }
8662  }
8663  }
8664  else if(SpeedTag == 77) // bot plat
8665  {
8666  for(int x = 0; x < 25; x++)
8667  {
8668  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8669  {
8670  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8671  EnterLocationName(4, LocationName, true);
8672  break;
8673  }
8674  }
8675  }
8676  else if(SpeedTag == 78) // l plat
8677  {
8678  for(int x = 0; x < 25; x++)
8679  {
8680  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8681  {
8682  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8683  EnterLocationName(5, LocationName, true);
8684  break;
8685  }
8686  }
8687  }
8688  else if(SpeedTag == 79) // r plat
8689  {
8690  for(int x = 0; x < 25; x++)
8691  {
8692  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8693  {
8694  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8695  EnterLocationName(6, LocationName, true);
8696  break;
8697  }
8698  }
8699  }
8700  else if(SpeedTag == 96) // conc
8701  {
8702  for(int x = 0; x < 28; x++)
8703  {
8704  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8705  {
8706  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8707  EnterLocationName(7, LocationName, true);
8708  break;
8709  }
8710  }
8711  }
8712  else if(SpeedTag == 129) // vert footbridge
8713  {
8714  for(int x = 0; x < 8; x++)
8715  {
8716  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8717  {
8718  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8719  EnterLocationName(8, LocationName, true);
8720  break;
8721  }
8722  }
8723  }
8724  else if(SpeedTag == 130) // hor footbridge
8725  {
8726  for(int x = 0; x < 8; x++)
8727  {
8728  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8729  {
8730  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8731  EnterLocationName(9, LocationName, true);
8732  break;
8733  }
8734  }
8735  }
8736  else if(SpeedTag == 145) // vert u'pass
8737  {
8738  for(int x = 0; x < 8; x++)
8739  {
8740  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8741  {
8742  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8743  EnterLocationName(11, LocationName, true);
8744  break;
8745  }
8746  }
8747  }
8748  else if(SpeedTag == 146) // hor u'pass
8749  {
8750  for(int x = 0; x < 8; x++)
8751  {
8752  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8753  {
8754  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8755  EnterLocationName(12, LocationName, true);
8756  break;
8757  }
8758  }
8759  }
8760  else if(SpeedTag == 131) // named location
8761  {
8762  for(int x = 0; x < 4; x++)
8763  {
8764  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8765  {
8766  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8767  EnterLocationName(10, LocationName, true);
8768  break;
8769  }
8770  }
8771  }
8772 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8773  Utilities->CallLogPop(580);
8774 }
8775 
8776 // ---------------------------------------------------------------------------
8777 
8778 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8779 /*
8780  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8781  true if a LocationName is found, and also returns the name and the adjusted vector position.
8782 */
8783 {
8784  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8785  AnsiString(SpeedTag));
8786  bool FoundFlag;
8787  TIMPair IMPair;
8788  TTrackVectorIterator TempElement;
8789  int Position;
8790 
8791  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8792  if(FoundFlag)
8793  {
8794  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8795  {
8796  TempElement = InactiveTrackVector.begin() + IMPair.first;
8797  if(TempElement->LocationName != "")
8798  {
8799  LocationName = TempElement->LocationName;
8800  FoundElement = IMPair.first;
8801  Utilities->CallLogPop(581);
8802  return(true);
8803  }
8804  }
8805  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8806  {
8807  TempElement = InactiveTrackVector.begin() + IMPair.second;
8808  if(TempElement->LocationName != "")
8809  {
8810  LocationName = TempElement->LocationName;
8811  FoundElement = IMPair.second;
8812  Utilities->CallLogPop(582);
8813  return(true);
8814  }
8815  }
8816  }
8817  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8818  if(FoundFlag)
8819  {
8820  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8821  {
8822  TempElement = TrackVector.begin() + Position;
8823  if(TempElement->LocationName != "")
8824  {
8825  LocationName = TempElement->LocationName;
8826  FoundElement = -1 - Position;
8827  Utilities->CallLogPop(583);
8828  return(true);
8829  }
8830  }
8831  }
8832  Utilities->CallLogPop(584);
8833  return(false);
8834 }
8835 
8836 // ---------------------------------------------------------------------------
8837 
8838 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8839 {
8840 // check quantity in map & vectors match
8841  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
8842  unsigned int Count = 0;
8843 
8844  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
8845  {
8846  Utilities->CallLogPop(2059);
8847  return;
8848  }
8849  AnsiString SName, TName, ErrorString;
8850 
8851  for(unsigned int x = 0; x < TrackVector.size(); x++)
8852  {
8853  if(TrackVector.at(x).FixedNamedLocationElement)
8854  {
8855  if(TrackVector.at(x).TrackType != FootCrossing)
8856  {
8857  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
8858  AnsiString(Caller));
8859  }
8860  Count++;
8861  }
8862  }
8863  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8864  {
8865  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8866  {
8867  if((InactiveTrackVector.at(x).TrackType != Platform) && (InactiveTrackVector.at(x).TrackType != NamedNonStationLocation) &&
8868  (InactiveTrackVector.at(x).TrackType != Concourse))
8869  {
8870  throw Exception
8871  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
8872  AnsiString(Caller));
8873  }
8874  Count++;
8875  }
8876  }
8877  if(LocationNameMultiMap.size() != Count)
8878  {
8879  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
8880  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8881  }
8882 // check all entries in both vectors match entries in name multimap
8884 
8885  for(unsigned int x = 0; x < TrackVector.size(); x++)
8886  {
8887  if(TrackVector.at(x).FixedNamedLocationElement)
8888  {
8889  SName = TrackVector.at(x).LocationName;
8890  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
8891  if(ErrorString != "")
8892  {
8893  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
8894  }
8895  if(SNIt->second != -1 - (int)x)
8896  {
8897  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8898  AnsiString(Caller));
8899  }
8900  }
8901  // check corresponding platform for all Timetable entries that aren't empty
8902  TName = TrackVector.at(x).ActiveTrackElementName;
8903  TIMPair IMPair;
8904  bool FoundFlag = false;
8905  if(TName != "")
8906  {
8907  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackVector.at(x).HLoc, TrackVector.at(x).VLoc, FoundFlag);
8908  if(FoundFlag)
8909  {
8910  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
8912  {
8913  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8914  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8915  }
8916  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
8917  {
8918  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackVector.at(x).HLoc) +
8919  " & V " + AnsiString(TrackVector.at(x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
8920  AnsiString(Caller));
8921  }
8922  }
8923  else
8924  {
8925  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackVector.at(x).HLoc) + " & V " +
8926  AnsiString(TrackVector.at(x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
8927  }
8928  }
8929  }
8930  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
8931  {
8932  if(InactiveTrackVector.at(x).FixedNamedLocationElement)
8933  {
8934  SName = InactiveTrackVector.at(x).LocationName;
8935  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
8936  if(ErrorString != "")
8937  {
8938  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
8939  }
8940  if(SNIt->second != (int)x)
8941  {
8942  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
8943  AnsiString(Caller));
8944  }
8945  }
8946  }
8947  Utilities->CallLogPop(585);
8948 }
8949 
8950 // ---------------------------------------------------------------------------
8951 
8953  AnsiString &ErrorString)
8954 {
8955 /*
8956  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
8957  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
8958  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
8959 */
8960  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
8961  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
8962  ErrorString = "";
8963  bool FoundFlag = false;
8964  TLocationNameMultiMapIterator SNIterator;
8965  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8966 
8967  if(SNRange.first == SNRange.second)
8968  {
8969  ErrorString = "Error, Name " + LocationName + " not found in map";
8970  Utilities->CallLogPop(586);
8971  return(SNRange.first);
8972  }
8973  else
8974  {
8975  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8976  {
8977  if(SNIterator->second < 0)
8978  {
8979  int TVPos = -1 - SNIterator->second;
8980  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
8981  if(TVIt == TrackElement)
8982  {
8983  FoundFlag = true;
8984  Utilities->CallLogPop(587);
8985  return(SNIterator);
8986  }
8987  }
8988  else
8989  {
8990  int ITVPos = SNIterator->second;
8991  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
8992  if(ITVIt == TrackElement)
8993  {
8994  FoundFlag = true;
8995  Utilities->CallLogPop(588);
8996  return(SNIterator);
8997  }
8998  }
8999  }
9000  }
9001  if(!FoundFlag)
9002  {
9003  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9004  }
9005  Utilities->CallLogPop(589);
9006  return(SNIterator);
9007 }
9008 
9009 // ---------------------------------------------------------------------------
9010 
9011 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9012 {
9013 /*
9014  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9015  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9016 */
9017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9018  TLocationNameMultiMapEntry LocationNameEntry;
9019 
9020  LocationNameEntry.first = NewName;
9021  LocationNameEntry.second = SNIterator->second;
9022  LocationNameMultiMap.erase(SNIterator);
9023  LocationNameMultiMap.insert(LocationNameEntry);
9024  Utilities->CallLogPop(590);
9025 }
9026 
9027 // ---------------------------------------------------------------------------
9028 
9030 {
9031 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9032  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9033  if(Position < 0) // footcrossing
9034  {
9035  int TruePos = -1 - Position;
9036  // new check at v0.2b
9037  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9038  {
9039  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9040  }
9041  Utilities->CallLogPop(591);
9042  return (TrackVector.begin() + TruePos);
9043  }
9044  else
9045  {
9046  // new check at v0.2b
9047  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9048  {
9049  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9050  }
9051  Utilities->CallLogPop(592);
9052  return (InactiveTrackVector.begin() + Position);
9053  }
9054 }
9055 
9056 // ---------------------------------------------------------------------------
9057 
9058 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9059 {
9060 /*
9061  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9062  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9063  LocationNameMultiMap.
9064 */
9065  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9066  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9067  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9068 
9069  if(!InactiveTrack2MultiMap.empty())
9070  {
9071  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9072  InactiveTrack2MultiMapIterator++)
9073  {
9074  if(InactiveTrack2MultiMapIterator->second > VecPos)
9075  {
9076  InactiveTrack2MultiMapIterator->second--;
9077  }
9078  // can't be == VecPos as that position erased
9079  }
9080  }
9081  if(!LocationNameMultiMap.empty())
9082  {
9083  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9084  LocationNameMultiMapIterator++)
9085  {
9086  if(LocationNameMultiMapIterator->second < 0)
9087  {
9088  continue; // deal with TrackVectors separately
9089  }
9090  if(LocationNameMultiMapIterator->second > (int)VecPos)
9091  {
9092  LocationNameMultiMapIterator->second--;
9093  }
9094  }
9095  }
9096  Utilities->CallLogPop(593);
9097 }
9098 
9099 // ---------------------------------------------------------------------------
9100 
9101 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9102 {
9103 /*
9104  After an element has been erased from the track vector, all the later elements are moved down one. This function
9105  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9106  LocationNameMultiMap.
9107 */
9108  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9109  TTrackMapIterator TrackMapIterator;
9110  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9111 
9112  if(!TrackMap.empty())
9113  {
9114  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9115  {
9116  if(TrackMapIterator->second > VecPos)
9117  {
9118  TrackMapIterator->second--;
9119  }
9120  // can't be == VecPos as that position erased
9121  }
9122  }
9123  if(!LocationNameMultiMap.empty())
9124  {
9125  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9126  LocationNameMultiMapIterator++)
9127  {
9128  if(LocationNameMultiMapIterator->second >= 0)
9129  {
9130  continue; // deal with InactiveTrackVectors separately
9131  }
9132  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9133  // Val -1 -2 -3 -4 -5 -6 -7 -8
9134  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9135  {
9136  LocationNameMultiMapIterator->second++;
9137  }
9138  }
9139  }
9140  for(unsigned int x = 0; x < TrackVector.size(); x++)
9141  {
9142  TTrackElement &TkEl = TrackVector.at(x); // no need to check so use this to speed up
9143  if(TkEl.TrackType == GapJump)
9144  {
9145  // position 0 is the gap
9146  if(TkEl.Conn[0] == int(VecPos))
9147  {
9148  TkEl.Conn[0] = -1; // connected to a deleted gap
9149  continue;
9150  }
9151  if(TkEl.Conn[0] > int(VecPos))
9152  {
9153  TkEl.Conn[0]--;
9154  }
9155  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9156  {
9157  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9158  {
9159  TkEl.Conn[0] = -1;
9160  }
9161  }
9162  }
9163  }
9164  Utilities->CallLogPop(1433);
9165 }
9166 
9167 // ---------------------------------------------------------------------------
9168 
9170 /*
9171  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9172  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9173  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9174 */
9175 {
9176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9177  LocationNameMultiMap.clear();
9178  TLocationNameMultiMapEntry LocationNameEntry;
9179  TTrackElement TrackElement;
9180 
9181  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9182  {
9183  TrackElement = TrackVector.at(TVPos);
9184  if(TrackElement.FixedNamedLocationElement)
9185  {
9186  LocationNameEntry.first = TrackElement.LocationName;
9187  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9188  LocationNameMultiMap.insert(LocationNameEntry);
9189  }
9190  }
9191 
9192  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9193  {
9194  TrackElement = InactiveTrackVector.at(ITVPos);
9195  if(TrackElement.FixedNamedLocationElement)
9196  {
9197  LocationNameEntry.first = TrackElement.LocationName;
9198  LocationNameEntry.second = ITVPos;
9199  LocationNameMultiMap.insert(LocationNameEntry);
9200  }
9201  }
9202  Utilities->CallLogPop(594);
9203 }
9204 
9205 // ---------------------------------------------------------------------------
9206 
9208 // Return true if there is a named location present in the railway
9209 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9210 {
9211  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9212  TTrackVectorIterator ITVI;
9213 
9214  if(InactiveTrackVector.empty())
9215  {
9216  Utilities->CallLogPop(1343);
9217  return(false);
9218  }
9219  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9220  {
9221  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9222  {
9223  Utilities->CallLogPop(1404);
9224  return(true);
9225  }
9226  }
9227  Utilities->CallLogPop(1344);
9228  return(false);
9229 }
9230 
9231 // ---------------------------------------------------------------------------
9232 
9234 /*
9235  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9236 */
9237 {
9238  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9239 // ResetDistanceElements(6);
9240  for(unsigned int x = 0; x < TrackVector.size(); x++)
9241  {
9242  TTrackElement &TE = TrackElementAt(718, x);
9245  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9246  {
9249  }
9250  }
9251 /* old function
9252  if((TrackVector.at(x).TrackType == Points) || (TrackVector.at(x).TrackType == Crossover) || (TrackVector.at(x).TrackType == Bridge))
9253  {
9254  SetOneDefaultTrackLength(2, TrackVector.at(x), 0);
9255  SetOneDefaultTrackLength(3, TrackVector.at(x), 2);
9256  }
9257  else
9258  {
9259  SetOneDefaultTrackLength(4, TrackVector.at(x), 0);
9260  }
9261  }
9262 */
9263  Utilities->CallLogPop(617);
9264 }
9265 
9266 // ---------------------------------------------------------------------------
9267 
9268 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9269 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9270 {
9271  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9272  for(unsigned int x = 0; x < TrackVector.size(); x++)
9273  {
9274  TTrackElement TempElement = TrackVector.at(x);
9275  if(TempElement.Length01 > -1)
9276  {
9277  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9278  }
9279  if(TempElement.Length23 > -1)
9280  {
9281  MarkOneLength(2, TempElement, false, Disp);
9282  }
9283  }
9284  Disp->Update();
9285  Utilities->CallLogPop(618);
9286 }
9287 
9288 // ---------------------------------------------------------------------------
9289 
9290 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9291 /*
9292  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
9293  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9294  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9295  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9296  track as indicated by FirstTrack (true for track01 & false for track23).
9297 */
9298 {
9299  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9300  AnsiString((short)FirstTrack));
9301  bool LengthDifferent = false, SpeedDifferent = false;
9302 
9303  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9304  {
9305  Utilities->CallLogPop(619);
9306  return;
9307  }
9308  int EXArray[16][2] =
9309  {{4, 6}, {2, 8}, // horizontal & vertical
9310  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9311  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9312  {1, 9}, {3, 7}}; // forward & reverse diagonals
9313 
9314  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9315  Graphics::TBitmap *Bitmap;
9316 
9317  if(FirstTrack)
9318  {
9319  InLink = TrackElement.Link[0];
9320  OutLink = TrackElement.Link[1];
9321  }
9322  else
9323  {
9324  InLink = TrackElement.Link[2];
9325  OutLink = TrackElement.Link[3];
9326  }
9327  for(int x = 0; x < 16; x++)
9328  {
9329  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9330  {
9331  Index = x;
9332  }
9333  }
9334  if(Index == -1)
9335  {
9336  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9337  }
9338 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9339  the graphic for each of which is different because of the shape of the overbridge. The basic
9340  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9341  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9342  int BrEXArray[24][2] = {
9343  {4,6},{2,8},{1,9},{3,7},
9344  {1,9},{3,7},{1,9},{3,7},
9345  {2,8},{4,6},{2,8},{4,6}
9346 */
9347  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9348  {
9349  if(Index == 1)
9350  {
9351  if(TrackElement.SpeedTag == 49)
9352  {
9353  BrNum = 1 + 16;
9354  }
9355  else if(TrackElement.SpeedTag == 54)
9356  {
9357  BrNum = 8 + 16;
9358  }
9359  else if(TrackElement.SpeedTag == 55)
9360  {
9361  BrNum = 10 + 16;
9362  }
9363  }
9364  else if(Index == 0)
9365  {
9366  if(TrackElement.SpeedTag == 48)
9367  {
9368  BrNum = 0 + 16;
9369  }
9370  else if(TrackElement.SpeedTag == 58)
9371  {
9372  BrNum = 11 + 16;
9373  }
9374  else if(TrackElement.SpeedTag == 59)
9375  {
9376  BrNum = 9 + 16;
9377  }
9378  }
9379  else if(Index == 14)
9380  {
9381  if(TrackElement.SpeedTag == 50)
9382  {
9383  BrNum = 2 + 16;
9384  }
9385  else if(TrackElement.SpeedTag == 52)
9386  {
9387  BrNum = 4 + 16;
9388  }
9389  else if(TrackElement.SpeedTag == 57)
9390  {
9391  BrNum = 6 + 16;
9392  }
9393  }
9394  else if(Index == 15)
9395  {
9396  if(TrackElement.SpeedTag == 51)
9397  {
9398  BrNum = 3 + 16;
9399  }
9400  else if(TrackElement.SpeedTag == 53)
9401  {
9402  BrNum = 7 + 16;
9403  }
9404  else if(TrackElement.SpeedTag == 56)
9405  {
9406  BrNum = 5 + 16;
9407  }
9408  }
9409  }
9410  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9411  {
9412  GrNum = BrNum;
9413  }
9414  else
9415  {
9416  GrNum = Index;
9417  }
9418  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9419  {
9420  if(GrNum > 15) // underbridge
9421  {
9422  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9423  }
9424  else
9425  {
9426  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9427  }
9428  if(TrackElement.SpeedTag == 64)
9429  {
9430  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9431  }
9432  if(TrackElement.SpeedTag == 65)
9433  {
9435  }
9436  if(TrackElement.SpeedTag == 66)
9437  {
9439  }
9440  if(TrackElement.SpeedTag == 67)
9441  {
9443  }
9444  if(TrackElement.SpeedTag == 80)
9445  {
9446  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9447  }
9448  if(TrackElement.SpeedTag == 81)
9449  {
9451  }
9452  if(TrackElement.SpeedTag == 82)
9453  {
9455  }
9456  if(TrackElement.SpeedTag == 83)
9457  {
9459  }
9460  if(TrackElement.SpeedTag == 84)
9461  {
9463  }
9464  if(TrackElement.SpeedTag == 85)
9465  {
9467  }
9468  if(TrackElement.SpeedTag == 86)
9469  {
9471  }
9472  if(TrackElement.SpeedTag == 87)
9473  {
9475  }
9476  if(TrackElement.SpeedTag == 129)
9477  {
9478  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9479  }
9480  if(TrackElement.SpeedTag == 130)
9481  {
9483  }
9484  }
9485 
9486  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9487  {
9488  if(GrNum > 15) // underbridge
9489  {
9490  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9491  }
9492  else
9493  {
9494  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9495  }
9496  if(TrackElement.SpeedTag == 64)
9497  {
9498  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9499  }
9500  if(TrackElement.SpeedTag == 65)
9501  {
9502  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9503  }
9504  if(TrackElement.SpeedTag == 66)
9505  {
9506  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9507  }
9508  if(TrackElement.SpeedTag == 67)
9509  {
9510  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9511  }
9512  if(TrackElement.SpeedTag == 80)
9513  {
9514  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9515  }
9516  if(TrackElement.SpeedTag == 81)
9517  {
9518  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9519  }
9520  if(TrackElement.SpeedTag == 82)
9521  {
9522  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9523  }
9524  if(TrackElement.SpeedTag == 83)
9525  {
9526  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9527  }
9528  if(TrackElement.SpeedTag == 84)
9529  {
9530  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9531  }
9532  if(TrackElement.SpeedTag == 85)
9533  {
9534  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9535  }
9536  if(TrackElement.SpeedTag == 86)
9537  {
9538  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9539  }
9540  if(TrackElement.SpeedTag == 87)
9541  {
9542  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9543  }
9544  if(TrackElement.SpeedTag == 129)
9545  {
9546  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9547  }
9548  if(TrackElement.SpeedTag == 130)
9549  {
9550  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9551  }
9552  }
9553 
9554  else // SpeedDifferent only: red - use non sig graphics
9555  {
9556  if(GrNum > 15) // underbridge
9557  {
9558  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9559  }
9560  else
9561  {
9562  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9563  }
9564  if(TrackElement.SpeedTag == 64)
9565  {
9566  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9567  }
9568  if(TrackElement.SpeedTag == 65)
9569  {
9571  }
9572  if(TrackElement.SpeedTag == 66)
9573  {
9575  }
9576  if(TrackElement.SpeedTag == 67)
9577  {
9579  }
9580  if(TrackElement.SpeedTag == 80)
9581  {
9582  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9583  }
9584  if(TrackElement.SpeedTag == 81)
9585  {
9587  }
9588  if(TrackElement.SpeedTag == 82)
9589  {
9591  }
9592  if(TrackElement.SpeedTag == 83)
9593  {
9595  }
9596  if(TrackElement.SpeedTag == 84)
9597  {
9599  }
9600  if(TrackElement.SpeedTag == 85)
9601  {
9603  }
9604  if(TrackElement.SpeedTag == 86)
9605  {
9607  }
9608  if(TrackElement.SpeedTag == 87)
9609  {
9611  }
9612  if(TrackElement.SpeedTag == 129)
9613  {
9614  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9615  }
9616  if(TrackElement.SpeedTag == 130)
9617  {
9619  }
9620  }
9621  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9622  Utilities->CallLogPop(620);
9623 }
9624 
9625 // ---------------------------------------------------------------------------
9626 
9627 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9628 /* FirstTrack = LinkPos's 0 & 1
9629  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9630 */
9631 {
9632  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9633  AnsiString((short)FirstTrack));
9634  LengthDifferent = false;
9635  SpeedDifferent = false;
9636  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9637  {
9638  if(TrackElement.Length01 != DefaultTrackLength)
9639  {
9640  LengthDifferent = true;
9641  }
9642  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9643  {
9644  SpeedDifferent = true;
9645  }
9646  if(LengthDifferent || SpeedDifferent)
9647  {
9648  Utilities->CallLogPop(625);
9649  return(false);
9650  }
9651  Utilities->CallLogPop(626);
9652  return(true);
9653  }
9654 
9655  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9656  {
9657  if(TrackElement.Length23 != DefaultTrackLength)
9658  {
9659  LengthDifferent = true;
9660  }
9661  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9662  {
9663  SpeedDifferent = true;
9664  }
9665  if(LengthDifferent || SpeedDifferent)
9666  {
9667  Utilities->CallLogPop(627);
9668  return(false);
9669  }
9670  Utilities->CallLogPop(628);
9671  return(true);
9672  }
9673 
9674  else // any other 1 track element, including platforms being present
9675  {
9676  if(TrackElement.Length01 != DefaultTrackLength)
9677  {
9678  LengthDifferent = true;
9679  }
9680  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9681  {
9682  SpeedDifferent = true;
9683  }
9684  if(LengthDifferent || SpeedDifferent)
9685  {
9686  Utilities->CallLogPop(629);
9687  return(false);
9688  }
9689  Utilities->CallLogPop(630);
9690  return(true);
9691  }
9692 }
9693 
9694 // ---------------------------------------------------------------------------
9695 
9696 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9697 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9698 {
9699  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9700  AnsiString(VLoc));
9701  bool FoundFlag;
9702  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9703 
9704  if(!FoundFlag)
9705  {
9706  Utilities->CallLogPop(633);
9707  return(false);
9708  }
9709  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9710  {
9711  Utilities->CallLogPop(634);
9712  return(true); // only need to check first since if second is a platform the the first must be too
9713  }
9714  else
9715  {
9716  Utilities->CallLogPop(635);
9717  return(false);
9718  }
9719 }
9720 
9721 // ---------------------------------------------------------------------------
9722 
9723 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9724 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9725 {
9726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9727  AnsiString(VLoc));
9728  bool FoundFlag;
9729  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9730 
9731  if(!FoundFlag)
9732  {
9733  Utilities->CallLogPop(636);
9734  return(false);
9735  }
9737  {
9738  Utilities->CallLogPop(637);
9739  return(true); // only need to check first since only one used for NamedNonStationLocations
9740  }
9741  else
9742  {
9743  Utilities->CallLogPop(638);
9744  return(false);
9745  }
9746 }
9747 
9748 // ---------------------------------------------------------------------------
9749 
9751 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9752  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9753  the front of train stop points for each direction.
9754  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9755  end (unless buffers at one or both ends in which case stop points are the end elements).
9756  Note that for a single element the stop point is the element itself (formula doesn't apply).
9757  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9758  repeating the procedure for every element. At the end all unused values are returned to -1.
9759  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9760 */
9761 {
9762  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9763  TTrackElement TempElement, StartElement;
9764  AnsiString TempName;
9765  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9766  bool ForwardSet, ReverseSet;
9767 
9768  for(unsigned int x = 0; x < TrackVector.size(); x++)
9769  {
9770  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9771  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9772  }
9773  for(unsigned int x = 0; x < TrackVector.size(); x++)
9774  {
9775  ForwardSet = false;
9776  ReverseSet = false;
9777  TempElement = TrackVector.at(x);
9778  VecPos = x;
9779  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9780  // 2nd condition incl so don't re-examine elements with stop links set to 5
9781  {
9782  TempName = TempElement.ActiveTrackElementName;
9783  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9784  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9785  // an element linked at both ends where both links are also named elements
9786  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9787  {
9788  continue; // looking for an end element so skip this one
9789  }
9790  else // reached one end
9791  {
9792  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9793  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9794  // single named element linked at both ends
9795  {
9796  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
9797  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
9798  continue;
9799  }
9800  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9801  // single named buffer element (LinkPos 1 is the non-buffer end)
9802  {
9803  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
9804  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
9805  continue;
9806  }
9807  else
9808  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
9809  // and platforms always on straight (conns 0 & 1) section of points
9810  {
9811  for(int y = 0; y < 2; y++)
9812  {
9813  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
9814  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
9815 /* TTrackElement Temp1 = TempElement;
9816  ***********New section, compiles but not checked - does bit below need to be else if?
9817  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
9818  {
9819  //search along Dir direction until find other end, skip if Dir facing buffer end
9820  int NewDir = Dir;
9821  int NewVecPos;
9822  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
9823  {
9824  NewVecPos = Temp1.Conn[NewDir];
9825  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
9826  Temp1 = TrackElementAt(601, NewVecPos);
9827  }
9828  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
9829  {
9830  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
9831  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
9832  }
9833  }
9834  ***************
9835 */
9836  // end may be linked at both ends but only one link named, or buffer with linked element named
9837  // if a buffer then the named linkpos has to be 1
9838  // already dealt with all types of single element so at least 2 linked named element
9839  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
9840  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
9841  {
9842  StartElement = TempElement;
9843  StartVecPos = VecPos;
9844  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
9845  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
9846  EntryPos = 1 - Dir;
9847  StartEntryPos = 1 - Dir;
9848  Count = 1;
9849  // work along named elements until find the other end
9850  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
9851  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
9852  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
9853  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
9854  // all stop link pos's are set to 5
9855  {
9856  VecPos = TempElement.Conn[1 - EntryPos];
9857  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9858  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
9859  EntryPos = TempEntryPos;
9860  Count++;
9861  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
9862  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
9863  }
9864  // here when reached other end, maybe buffers, continuation or last named linked element
9865  if(TrackElementAt(57, VecPos).TrackType == Buffers)
9866  // terminal station, set end elements as stop elements
9867  {
9868  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
9869  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
9870  continue;
9871  }
9872  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
9873  // terminal station, set end elements as stop elements
9874  {
9875  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
9876  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9877  continue;
9878  }
9879  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
9880  // NonStationLocation so set end elements as stop elements
9881  {
9882  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
9883  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
9884  continue;
9885  }
9886  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
9887  ForwardNumber = ((Count + 1) / 2) + 1;
9888  ReverseNumber = (Count - ForwardNumber) + 1;
9889  Count = 1; // starting value
9890  EntryPos = 1 - Dir;
9891  TempElement = StartElement;
9892  VecPos = StartVecPos;
9893  if(Count == ForwardNumber)
9894  {
9895  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
9896  ForwardSet = true;
9897  }
9898  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
9899  {
9900  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9901  ReverseSet = true;
9902  }
9903  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
9904  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
9905  {
9906  VecPos = TempElement.Conn[1 - EntryPos];
9907  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
9908  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
9909  EntryPos = TempEntryPos;
9910  Count++;
9911  if(Count == ForwardNumber)
9912  {
9913  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
9914  ForwardSet = true;
9915  }
9916  if(Count == ReverseNumber)
9917  {
9918  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
9919  ReverseSet = true;
9920  }
9921  }
9922  }
9923  }
9924  }
9925  }
9926  }
9927  }
9928  for(unsigned int x = 0; x < TrackVector.size(); x++)
9929  {
9930  if(TrackVector.at(x).StationEntryStopLinkPos1 == 5)
9931  {
9932  TrackVector.at(x).StationEntryStopLinkPos1 = -1;
9933  }
9934  if(TrackVector.at(x).StationEntryStopLinkPos2 == 5)
9935  {
9936  TrackVector.at(x).StationEntryStopLinkPos2 = -1;
9937  }
9938  }
9939  Utilities->CallLogPop(639);
9940 }
9941 
9942 // ---------------------------------------------------------------------------
9943 
9944 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
9945 {
9946  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
9947  TTrackElement Next;
9948 
9950  while(ReturnNextInactiveTrackElement(1, Next))
9951  {
9952  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9953  {
9954  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
9955  // need striped graphics
9956  {
9957  if(Next.SpeedTag == 76)
9958  {
9959  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
9960  }
9961  else if(Next.SpeedTag == 77)
9962  {
9963  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
9964  }
9965  else if(Next.SpeedTag == 78)
9966  {
9967  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
9968  }
9969  else if(Next.SpeedTag == 79)
9970  {
9971  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
9972  }
9973  else if(Next.SpeedTag == 96)
9974  {
9975  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
9976  }
9977  else if(Next.SpeedTag == 131)
9978  {
9979  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
9980  }
9981  }
9982  else
9983  {
9984  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
9985  }
9986  }
9987  }
9988 
9989  NextTrackElementPtr = TrackVector.begin();
9990  while(ReturnNextTrackElement(1, Next))
9991  {
9992  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
9993  {
9994  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
9995  {
9996  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
9997  {
9998  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
9999  }
10000  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10001  {
10002  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10003  }
10004  }
10005  else
10006  {
10007  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10008  }
10009  }
10010  }
10011  Disp->Update();
10012  Utilities->CallLogPop(640);
10013 }
10014 
10015 // ---------------------------------------------------------------------------
10016 
10017 void TTrack::PlotSmallRedGap(int Caller)
10018 {
10019  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10021  Utilities->CallLogPop(1346);
10022 }
10023 
10024 // ---------------------------------------------------------------------------
10025 
10026 void TTrack::TrackClear(int Caller)
10027 {
10028  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10029  TrackVector.clear();
10030  InactiveTrackVector.clear();
10031  TrackMap.clear();
10033  if(TextHandler->TextVector.size() == 0)
10034  {
10035  Display->DisplayOffsetH = 0;
10036  Display->DisplayOffsetV = 0;
10043  HLocMin = 2000000000;
10044  HLocMax = -2000000000;
10045  VLocMin = 2000000000;
10046  VLocMax = -2000000000;
10047  }
10048  else
10049  {
10050  CalcHLocMinEtc(4);
10051  }
10052  Utilities->CallLogPop(1347);
10053 }
10054 
10055 // ---------------------------------------------------------------------------
10056 
10057 void TTrack::CalcHLocMinEtc(int Caller)
10058 {
10059  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10060  HLocMin = 2000000000;
10061  VLocMin = 2000000000;
10062  HLocMax = -2000000000;
10063  VLocMax = -2000000000;
10064  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10065  {
10066  if(TrackVector.at(x).SpeedTag == 0)
10067  {
10068  continue; // skip erase elements or would interfere with Min & Max values
10069  }
10070  if(TrackVector.at(x).HLoc - 1 < HLocMin)
10071  {
10072  HLocMin = TrackVector.at(x).HLoc - 1; // add one all round
10073  }
10074  if(TrackVector.at(x).HLoc + 1 > HLocMax)
10075  {
10076  HLocMax = TrackVector.at(x).HLoc + 1;
10077  }
10078  if(TrackVector.at(x).VLoc - 1 < VLocMin)
10079  {
10080  VLocMin = TrackVector.at(x).VLoc - 1;
10081  }
10082  if(TrackVector.at(x).VLoc + 1 > VLocMax)
10083  {
10084  VLocMax = TrackVector.at(x).VLoc + 1;
10085  }
10086  }
10087  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10088  {
10089  if(InactiveTrackVector.at(x).SpeedTag == 0)
10090  {
10091  continue; // shouldn't be any inactive erase elements but include anyway
10092  }
10093  if(InactiveTrackVector.at(x).HLoc - 1 < HLocMin)
10094  {
10095  HLocMin = InactiveTrackVector.at(x).HLoc - 1; // add one all round
10096  }
10097  if(InactiveTrackVector.at(x).HLoc + 1 > HLocMax)
10098  {
10099  HLocMax = InactiveTrackVector.at(x).HLoc + 1;
10100  }
10101  if(InactiveTrackVector.at(x).VLoc - 1 < VLocMin)
10102  {
10103  VLocMin = InactiveTrackVector.at(x).VLoc - 1;
10104  }
10105  if(InactiveTrackVector.at(x).VLoc + 1 > VLocMax)
10106  {
10107  VLocMax = InactiveTrackVector.at(x).VLoc + 1;
10108  }
10109  }
10110  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10111  {
10112 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10113  will fail as x will exceed the maximum value
10114  if(TextHandler->TextPtrAt(, x)->TextString == "")
10115  {
10116  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10117  }
10118 */
10119  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10120  if((TextH / 16) - 1 < HLocMin)
10121  {
10122  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10123  }
10124  if((TextH / 16) + 1 > HLocMax)
10125  {
10126  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10127  }
10128  if((TextV / 16) - 1 < VLocMin)
10129  {
10130  VLocMin = (TextV / 16) - 1;
10131  }
10132  if((TextV / 16) + 1 > VLocMax)
10133  {
10134  VLocMax = (TextV / 16) + 1;
10135  }
10136  }
10137  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10138  {
10139  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10140  {
10141  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10142  }
10143  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10144  {
10145  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10146  }
10147  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10148  {
10149  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10150  }
10151  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10152  {
10153  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10154  }
10155  }
10156 
10157  Utilities->CallLogPop(641);
10158 }
10159 
10160 // ---------------------------------------------------------------------------
10161 
10162 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10163  bool &UserGraphicFoundFlag)
10164 {
10165  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10166  TUserGraphicVector::iterator UserGraphicPtr;
10167 
10168  UserGraphicFoundFlag = false;
10169  if(!UserGraphicVector.empty())
10170  {
10171  int x = UserGraphicVector.size();
10172  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10173  {
10174  x--;
10175  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10176  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10177  {
10178  UserGraphicItem = x;
10179  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10180  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10181  UserGraphicFoundFlag = true;
10182  Utilities->CallLogPop(2177);
10183  return;
10184  } // if ....
10185 
10186  } // for UserGraphicPtr...
10187  } // if !UserGraphicVector...
10188 
10189  Utilities->CallLogPop(2197);
10190 }
10191 
10192 // ---------------------------------------------------------------------------
10193 
10195 {
10196  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10197  TrackElement.LogTrack(11));
10198  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10199  int SpeedTag = TrackElement.SpeedTag;
10200 
10201  if(SpeedTag < 1)
10202  {
10203  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10204  }
10205  switch(SpeedTag)
10206  {
10207  case 76: // t platform
10208  GraphicOutput = RailGraphics->gl76Striped;
10209  break;
10210 
10211  case 77: // h platform
10212  GraphicOutput = RailGraphics->bm77Striped;
10213  break;
10214 
10215  case 78: // v platform
10216  GraphicOutput = RailGraphics->bm78Striped;
10217  break;
10218 
10219  case 79: // r platform
10220  GraphicOutput = RailGraphics->gl79Striped;
10221  break;
10222 
10223  case 96: // concourse
10224  GraphicOutput = RailGraphics->ConcourseStriped;
10225  break;
10226 
10227  case 129: // v footbridge
10228  GraphicOutput = RailGraphics->gl129Striped;
10229  break;
10230 
10231  case 130: // h footbridge
10232  GraphicOutput = RailGraphics->gl130Striped;
10233  break;
10234 
10235  case 131: // non-station named loc
10236  GraphicOutput = RailGraphics->bmNameStriped;
10237  break;
10238 
10239  case 145: // v u'pass
10240  GraphicOutput = RailGraphics->gl145Striped;
10241  break;
10242 
10243  case 146: // h u'pass
10244  GraphicOutput = RailGraphics->gl146Striped;
10245  break;
10246 
10247  default:
10248  GraphicOutput = TrackElement.GraphicPtr;
10249  break;
10250  }
10251  Utilities->CallLogPop(642);
10252  return(GraphicOutput);
10253 }
10254 
10255 // ---------------------------------------------------------------------------
10256 
10258 {
10259  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10260  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10261  {
10262  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10263  }
10264  Utilities->CallLogPop(643);
10265  return(TrackVector.at(At));
10266 }
10267 
10268 // ---------------------------------------------------------------------------
10269 
10271 {
10272  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10273  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10274  {
10275  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10276  " in InactiveTrackElementAt");
10277  }
10278  Utilities->CallLogPop(644);
10279  return(InactiveTrackVector.at(At));
10280 }
10281 
10282 // ---------------------------------------------------------------------------
10283 
10284 bool TTrack::BlankElementAt(int Caller, int At) const
10285 {
10286  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10287  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10288  {
10289  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10290  }
10291  if(TrackVector.at(At).SpeedTag == 0)
10292  {
10293  Utilities->CallLogPop(645);
10294  return(true);
10295  }
10296  else
10297  {
10298  Utilities->CallLogPop(646);
10299  return(false);
10300  }
10301 }
10302 
10303 // ---------------------------------------------------------------------------
10304 
10305 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10306 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10307  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10308  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10309  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10310  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10311 */
10312 {
10313  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10314  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10315  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10316  TLocationNameMultiMapIterator SNIterator;
10317  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10318 
10319  if(SNRange.first == SNRange.second)
10320  {
10321  Utilities->CallLogPop(972);
10322  return(false); // should have been caught earlier but include for completeness
10323  }
10324  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10325  {
10326  if(SNIterator->second < 0)
10327  {
10328  continue; // exclude footcrossings
10329  }
10330  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10331  if(InactiveElement.TrackType == Concourse)
10332  {
10333  continue; // only interested in locations where ActiveTrackElementName may be set
10334  }
10335  THVPair HVPair;
10336  HVPair.first = InactiveElement.HLoc;
10337  HVPair.second = InactiveElement.VLoc;
10338  if(TrackMap.find(HVPair) == TrackMap.end())
10339  {
10340  throw Exception
10341  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10342  }
10343  int TVPos = TrackMap.find(HVPair)->second;
10344  FirstNamedElement = TrackElementAt(560, TVPos);
10345  // first check linked on both sides, skip the check if not
10346  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10347  {
10348  continue;
10349  }
10350  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10351  // ActiveTrackElementNames are points and excluding trailing connections for points
10352  FirstNamedExitPos = 0;
10353  {
10354  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10355  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10356  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10357  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10358  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10359  {
10360  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10361  {
10362  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10363  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10364  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10365  // success, now check FirstNamedElement link not trailing points & if so all OK
10366  {
10367  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10368  {
10369  Utilities->CallLogPop(1002);
10370  return(true);
10371  }
10372  }
10373  }
10374  }
10375  }
10376  // failed, try link 1
10377  FirstNamedExitPos = 1;
10378  {
10379  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10380  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10381  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10382  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10383  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10384  {
10385  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10386  {
10387  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10388  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10389  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10390  // success, now check FirstNamedElement link not trailing points & if so all OK
10391  {
10392  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10393  {
10394  Utilities->CallLogPop(1003);
10395  return(true);
10396  }
10397  }
10398  }
10399  }
10400  }
10401  }
10402  Utilities->CallLogPop(1004);
10403  return(false);
10404 }
10405 
10406 // ---------------------------------------------------------------------------
10407 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10408  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10409 // for success need two linked named location elements, so that one element of each train can be at the location
10410 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10411 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10412 // the two trains will occupy these 4 elements
10413 // All are track vector positions, all but the input being references and set within the function.
10414 {
10415 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10416  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10417  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10418  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10419  splitting.
10420 */
10421  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10422  AnsiString(FirstNamedElementPos));
10423  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10424  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10425 
10426  SecondNamedElementPos = -1;
10427  FirstNamedLinkedElementPos = -1;
10428  SecondNamedLinkedElementPos = -1;
10429  TLocationNameMultiMapIterator SNIterator;
10430  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10431 
10432  if(SNRange.first == SNRange.second) // i.e. location name not in map
10433  {
10434  Utilities->CallLogPop(1005);
10435  return(false); // should have been caught earlier but include for completeness
10436  }
10437  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10438  {
10439  if(SNIterator->second < 0)
10440  {
10441  continue; // exclude footcrossings
10442  }
10443  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10444  if(InactiveElement.TrackType == Concourse)
10445  {
10446  continue; // only interested in locations where ActiveTrackElementName may be set
10447  }
10448  THVPair HVPair;
10449  HVPair.first = InactiveElement.HLoc;
10450  HVPair.second = InactiveElement.VLoc;
10451  if(TrackMap.find(HVPair) == TrackMap.end())
10452  {
10453  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10454  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10455  // then it won't be found in TrackMap but it's still legitimate.
10456  {
10457  continue;
10458  }
10459  else // for anything else throw the error
10460  {
10461  throw Exception
10462  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10463  );
10464  }
10465  }
10466  int TVPos = TrackMap.find(HVPair)->second;
10467  if(TVPos != FirstNamedElementPos)
10468  {
10469  continue; // looking for an exact match
10470  }
10471  FirstNamedElement = TrackElementAt(567, TVPos);
10472  // first check linked on both sides, skip the check if not
10473  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10474  {
10475  continue;
10476  }
10477  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10478  // ActiveTrackElementNames are points and excluding trailing connections for points
10479  FirstNamedExitPos = 0;
10480  {
10481  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10482  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10483  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10484  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10485  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10486  {
10487  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10488  {
10489  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10490  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10491  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10492  // success, now check FirstNamedElement link not trailing points & if so all OK
10493  {
10494  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10495  {
10496  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10497  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10498  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10499  Utilities->CallLogPop(1006);
10500  return(true);
10501  }
10502  }
10503  }
10504  }
10505  }
10506  // failed, try link 1
10507  FirstNamedExitPos = 1;
10508  {
10509  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10510  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10511  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10512  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10513  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10514  {
10515  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10516  {
10517  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10518  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10519  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10520  // success, now check FirstNamedElement link not trailing points & if so all OK
10521  {
10522  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10523  {
10524  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10525  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10526  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10527  Utilities->CallLogPop(1007);
10528  return(true);
10529  }
10530  }
10531  }
10532  }
10533  }
10534  }
10535  Utilities->CallLogPop(1008);
10536  return(false);
10537 }
10538 
10539 // ---------------------------------------------------------------------------
10540 
10541 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10542 {
10543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10544  TLocationNameMultiMapIterator SNIterator;
10545  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10546 
10547  if(SNRange.first != SNRange.second)
10548  {
10549  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10550  {
10551  if(SNIterator->second < 0)
10552  {
10553  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10554  }
10555  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10556  SNIterator->second).TrackType == NamedNonStationLocation))
10557  {
10558  Utilities->CallLogPop(1121);
10559  return(true);
10560  }
10561  }
10562  }
10563  Utilities->CallLogPop(848);
10564  return(false);
10565 }
10566 
10567 // ---------------------------------------------------------------------------
10568 
10569 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10570 {
10571 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10572  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10573  "," + AnsiString(SpeedTag));
10574  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10575  {
10576  Utilities->CallLogPop(949);
10577  return(false);
10578  }
10579  bool FoundFlag;
10580  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10581 
10582  if(!FoundFlag)
10583  {
10584  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10585  }
10586  TTrackElement IAElement;
10587 
10588  if(SpeedTag == 68) // top sig
10589  {
10590  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10591  {
10592  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10593  {
10594  IAElement = InactiveTrackElementAt(50, IMPair.first);
10595  }
10596  else
10597  {
10598  IAElement = InactiveTrackElementAt(51, IMPair.second);
10599  }
10600  if(IAElement.LocationName == "")
10601  {
10602 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10603  SignalPlatformGraphic = RailGraphics->gl76Striped;
10604  }
10605  else
10606  {
10607 // SignalPlatformGraphic = RailGraphics->Plat68;
10608  SignalPlatformGraphic = RailGraphics->gl76;
10609  }
10610  Utilities->CallLogPop(950);
10611  return(true);
10612  }
10613  }
10614  else if(SpeedTag == 69) // bot sig
10615  {
10616  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10617  {
10618  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10619  {
10620  IAElement = InactiveTrackElementAt(77, IMPair.first);
10621  }
10622  else
10623  {
10624  IAElement = InactiveTrackElementAt(78, IMPair.second);
10625  }
10626  if(IAElement.LocationName == "")
10627  {
10628 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10629  SignalPlatformGraphic = RailGraphics->bm77Striped;
10630  }
10631  else
10632  {
10633 // SignalPlatformGraphic = RailGraphics->Plat69;
10634  SignalPlatformGraphic = RailGraphics->bm77;
10635  }
10636  Utilities->CallLogPop(951);
10637  return(true);
10638  }
10639  }
10640  else if(SpeedTag == 70) // left sig
10641  {
10642  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10643  {
10644  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10645  {
10646  IAElement = InactiveTrackElementAt(55, IMPair.first);
10647  }
10648  else
10649  {
10650  IAElement = InactiveTrackElementAt(82, IMPair.second);
10651  }
10652  if(IAElement.LocationName == "")
10653  {
10654 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10655  SignalPlatformGraphic = RailGraphics->bm78Striped;
10656  }
10657  else
10658  {
10659 // SignalPlatformGraphic = RailGraphics->Plat70;
10660  SignalPlatformGraphic = RailGraphics->bm78;
10661  }
10662  Utilities->CallLogPop(952);
10663  return(true);
10664  }
10665  }
10666  else if(SpeedTag == 71) // right sig
10667  {
10668  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10669  {
10670  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10671  {
10672  IAElement = InactiveTrackElementAt(85, IMPair.first);
10673  }
10674  else
10675  {
10676  IAElement = InactiveTrackElementAt(86, IMPair.second);
10677  }
10678  if(IAElement.LocationName == "")
10679  {
10680 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10681  SignalPlatformGraphic = RailGraphics->gl79Striped;
10682  }
10683  else
10684  {
10685 // SignalPlatformGraphic = RailGraphics->Plat71;
10686  SignalPlatformGraphic = RailGraphics->gl79;
10687  }
10688  Utilities->CallLogPop(953);
10689  return(true);
10690  }
10691  }
10692  Utilities->CallLogPop(954);
10693  return(false);
10694 }
10695 
10696 // ---------------------------------------------------------------------------
10697 
10698 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10699 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10700 // false if not, if NextPos == -1, or if only own train on the track
10701 {
10702  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10703  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10704  if(NextEntryPos < 0)
10705  {
10706  Utilities->CallLogPop(1348);
10707  return(false);
10708  }
10709  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10710 
10711  if(TrackElement.TrackType != Bridge)
10712  {
10713  Utilities->CallLogPop(1349);
10714  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10715  }
10716 // bridge if reach here
10717  if(NextEntryPos > 1)
10718  {
10719  Utilities->CallLogPop(1350);
10720  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10721  }
10722  else
10723  {
10724  Utilities->CallLogPop(1351);
10725  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10726  }
10727 }
10728 
10729 // ---------------------------------------------------------------------------
10730 
10732 {
10733  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
10734  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
10735  {
10736  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
10737  }
10738  Utilities->CallLogPop(1483);
10739  return(SelectVector.at(At));
10740 }
10741 
10742 // ---------------------------------------------------------------------------
10743 
10744 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
10745 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
10746 {
10747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
10748  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
10749  bool FoundFlag = false;
10750  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
10751  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
10752 
10753  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
10754  Utilities->CallLogPop(1538);
10755  return(FoundFlag);
10756 }
10757 
10758 // ---------------------------------------------------------------------------
10759 
10760 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
10761 {
10762 // return true if find an inactive element called 'Name'
10763  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
10764  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
10765  bool FoundFlag = false;
10766 
10767  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10768  {
10769  if(InactiveTrackVector.at(x).LocationName == Name)
10770  {
10771  FoundFlag = true;
10772  int V = InactiveTrackVector.at(x).VLoc;
10773  int H = InactiveTrackVector.at(x).HLoc;
10774  if(V > VLocHi)
10775  {
10776  VLocHi = V;
10777  }
10778  if(V < VLocLo)
10779  {
10780  VLocLo = V;
10781  }
10782  if(H < HLoc)
10783  {
10784  HLoc = H;
10785  }
10786  }
10787  }
10788  if(FoundFlag)
10789  {
10790  VPosHi = 16 * VLocHi;
10791  VPosLo = 16 * VLocLo;
10792  HPos = 16 * HLoc;
10793  Utilities->CallLogPop(1562);
10794  return(true);
10795  }
10796  else
10797  {
10798  Utilities->CallLogPop(1563);
10799  return(false);
10800  }
10801 }
10802 
10803 // ---------------------------------------------------------------------------
10804 
10805 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
10806 {
10807 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
10808 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
10809  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
10810  AnsiString(EndTVPosition));
10811  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
10812  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
10813 
10814 // get H & V values for the element adjacent to Link[0] & Link[1]
10815  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
10816  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
10817  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
10818  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
10819 
10820 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
10821  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
10822  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
10823  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
10824  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
10825 
10826  if(Link0Squares <= Link1Squares)
10827  {
10828  Utilities->CallLogPop(1851);
10829  return(0);
10830  }
10831  else
10832  {
10833  Utilities->CallLogPop(1852);
10834  return(1);
10835  }
10836 }
10837 
10838 // ---------------------------------------------------------------------------
10839 
10840 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
10841 {
10842  // element can be points or any other type
10843  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
10844  AnsiString(LinkPos));
10845  Derail = false;
10846  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
10847 
10848  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
10849  {
10850  if(TE.Attribute == 0)
10851  {
10852  Utilities->CallLogPop(663);
10853  return(1); // Att == 0 & ExitPos == 1 represent straight
10854  }
10855  else
10856  {
10857  Utilities->CallLogPop(664);
10858  return(3); // Att == 1 & ExitPos == 3 represent diverging
10859  }
10860  }
10861  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
10862  {
10863  if((LinkPos == 1) && (TE.Attribute == 0))
10864  {
10865  Utilities->CallLogPop(665);
10866  return(0); // Att == 0 represents straight
10867  }
10868  else if(LinkPos == 1)
10869  {
10870  Derail = true;
10871  Utilities->CallLogPop(666);
10872  return(0);
10873  }
10874  else if((LinkPos == 3) && (TE.Attribute == 1))
10875  {
10876  Utilities->CallLogPop(667);
10877  return(0);
10878  }
10879  else if(LinkPos == 3)
10880  {
10881  Derail = true;
10882  Utilities->CallLogPop(668);
10883  return(0);
10884  }
10885  }
10886  else if(LinkPos == 0)
10887  {
10888  Utilities->CallLogPop(669);
10889  return(1);
10890  }
10891  else if(LinkPos == 1)
10892  {
10893  Utilities->CallLogPop(670);
10894  return(0);
10895  }
10896  else if(LinkPos == 2)
10897  {
10898  Utilities->CallLogPop(671);
10899  return(3);
10900  }
10901  else if(LinkPos == 3)
10902  {
10903  Utilities->CallLogPop(672);
10904  return(2);
10905  }
10906  throw Exception("Error, failure in GetExitPos"); // should never reach here
10907 }
10908 
10909 // ----------------------------------------------------------------------------
10910 
10912 {
10913  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
10914  LCVector.clear();
10915  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10916  {
10917  if(InactiveTrackVector.at(x).TrackType == LevelCrossing)
10918  {
10919  LCVector.push_back(x);
10920  }
10921  }
10922  Utilities->CallLogPop(1931);
10923  return;
10924 }
10925 
10926 // ---------------------------------------------------------------------------
10927 
10928 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
10929 /*
10930  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
10931  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
10932  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
10933  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
10934 */
10935 {
10936  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
10937  AnsiString(Link));
10938  bool FoundFlag;
10939 
10940  TrainID = -1;
10941  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
10942 
10943  if(!FoundFlag)
10944  {
10945  Utilities->CallLogPop(2001);
10946  return(false);
10947  }
10948  TTrackElement TE = TrackElementAt(882, VecPos);
10949 
10950  TrainID = TE.TrainIDOnElement;
10951  if(TE.TrackType == Bridge)
10952  {
10953  if(TE.TrainIDOnElement > -1)
10954  {
10955  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
10956  {
10957  TrainID = TE.TrainIDOnBridgeTrackPos01;
10958  }
10959  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
10960  {
10961  TrainID = TE.TrainIDOnBridgeTrackPos23;
10962  }
10963  else
10964  {
10965  TrainID = -1; // shouldn't ever reach here but be safe
10966  }
10967  }
10968  }
10969  if(TrainID == -1)
10970  {
10971  Utilities->CallLogPop(2002);
10972  return(false);
10973  }
10974 // now get the train
10975  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
10976 
10977  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
10978  {
10979  Utilities->CallLogPop(2003);
10980  return(true);
10981  }
10982  TrainID = -1;
10983  Utilities->CallLogPop(2004);
10984  return(false);
10985 }
10986 
10987 // ---------------------------------------------------------------------------
10988 
10989 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
10990 /* New at v1.2.0
10991  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
10992  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
10993  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
10994  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
10995  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
10996  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
10997  Each of these is examined in turn for each route element in the relevant position.
10998 */
10999 {
11000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11001  "," + AnsiString(DiagonalLinkNumber));
11002  TrainID = -1;
11003  TPrefDirElement TempPrefDirElement;
11004  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11005 
11006  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11007  {
11008  Utilities->CallLogPop(2027);
11009  return(true);
11010  }
11011  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11012  {
11013  Utilities->CallLogPop(2028);
11014  return(true);
11015  }
11016  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11017  {
11018  Utilities->CallLogPop(2029);
11019  return(true);
11020  }
11021  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11022  {
11023  Utilities->CallLogPop(2030);
11024  return(true);
11025  }
11026  Utilities->CallLogPop(2031);
11027  return(false);
11028 }
11029 
11030 // ---------------------------------------------------------------------------
11031 
11032 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11033 {
11034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11035  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11036  TUserGraphicItem UGI;
11037  AnsiString JustFileName = "";
11038 
11039  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11040  {
11041  UGI = UserGraphicVectorAt(17, x);
11042  int LastDelim = UGI.FileName.LastDelimiter('\\');
11043  if(LastDelim == 0) // can't find it so skip this item
11044  {
11045  continue;
11046  }
11047  else
11048  {
11049  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11050  }
11051  Utilities->SaveFileString(VecFile, JustFileName);
11052  Utilities->SaveFileInt(VecFile, UGI.HPos);
11053  Utilities->SaveFileInt(VecFile, UGI.VPos);
11054  }
11055  Utilities->CallLogPop(2178);
11056 }
11057 
11058 // ---------------------------------------------------------------------------
11059 
11060 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11061 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11062 {
11063  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11064  int NumPlats = 0;
11065  TTrackElement TempElement;
11066  int TempInt;
11067 
11068  typedef std::list<int> TNamePosList;
11069  TNamePosList NamePosList;
11070  typedef TNamePosList::iterator TNPLIt;
11071  TNPLIt NPLIt;
11072  typedef std::list<int> TOnePlatList;
11073  TOnePlatList OnePlatList;
11074  typedef TOnePlatList::iterator TOPLIt;
11075  TOPLIt OPLIt;
11076 
11077  NamePosList.clear();
11078  OnePlatList.clear();
11079  for(unsigned int x = 0; x < TrackVector.size(); x++)
11080  {
11081  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11082  {
11083  NamePosList.push_back(x);
11084  }
11085  }
11086  //NamePosList complete
11087 
11088  if(!NamePosList.empty()) //first value for the loop examination
11089  {
11090  OnePlatList.push_back(NamePosList.back());
11091  NamePosList.pop_back(); //erase from NPV as done with it here
11092  }
11093  while(!OnePlatList.empty()) //loop to examine all linked elements
11094  {
11095  TempInt = OnePlatList.front();
11096  TempElement = TrackElementAt(989, TempInt);
11097 
11098  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11099  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11100  {
11101  OnePlatList.push_back(TempElement.Conn[0]);
11102  NamePosList.erase(NPLIt);
11103  }
11104  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11105  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11106  {
11107  OnePlatList.push_back(TempElement.Conn[1]);
11108  NamePosList.erase(NPLIt);
11109  }
11110  //here when loaded any connecting links into OnePlatList, so can erase the front element
11111  OnePlatList.erase(OnePlatList.begin());
11112  if(OnePlatList.empty())
11113  {
11114  NumPlats++; //finished with current linked elements so can increment NumPlats
11115  if(!NamePosList.empty())
11116  {
11117  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11118  NamePosList.pop_back(); //erase from NPV as done with it there
11119  }
11120  }
11121  }
11122  Utilities->CallLogPop(2218);
11123  return(NumPlats);
11124 }
11125 
11126 // ---------------------------------------------------------------------------
11127 // UserGraphic, PrefDir & Route functions
11128 // ---------------------------------------------------------------------------
11129 
11131 {
11132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11133  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11134  {
11135  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11136  }
11137  Utilities->CallLogPop(2194);
11138  return(UserGraphicVector.at(At));
11139 }
11140 
11141 // ---------------------------------------------------------------------------
11142 
11143 int TOnePrefDir::LastElementNumber(int Caller) const
11144 {
11145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11146  int RetVal = PrefDirVector.size() - 1;
11147 
11148  if(RetVal < 0)
11149  {
11150  throw Exception("Return value negative in call to LastElementNumber");
11151  }
11152  Utilities->CallLogPop(114);
11153  return(RetVal);
11154 }
11155 
11156 // ---------------------------------------------------------------------------
11158 {
11159  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11160  if(PrefDirVector.empty())
11161  {
11162  throw Exception("PrefDirVector empty in call to LastElementPtr");
11163  }
11164  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11165 
11166  Utilities->CallLogPop(115);
11167  return(RetIT);
11168 }
11169 
11170 // ---------------------------------------------------------------------------
11172 {
11173  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11174  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11175  {
11176  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11177  }
11178  Utilities->CallLogPop(116);
11179  return(PrefDirVector.at(At));
11180 }
11181 
11182 // ---------------------------------------------------------------------------
11184 {
11185  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11186  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11187  {
11188  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11189  " in GetModifiablePrefDirElementAt");
11190  }
11191  Utilities->CallLogPop(117);
11192  return(PrefDirVector.at(At));
11193 }
11194 
11195 // ---------------------------------------------------------------------------
11197 {
11198  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11199  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11200  {
11201  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11202  }
11203  Utilities->CallLogPop(118);
11204  return(SearchVector.at(At));
11205 }
11206 
11207 // ---------------------------------------------------------------------------
11209 {
11210  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11211  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11212  {
11213  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11214  }
11215  Utilities->CallLogPop(119);
11216  return(SearchVector.at(At));
11217 }
11218 
11219 // ---------------------------------------------------------------------------
11220 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11221 /*
11222  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11223  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11224  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11225  set in later functions.
11226 */
11227 {
11228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11229  ClearPrefDir();
11230  int TrackVectorPosition;
11231  TTrackElement TrackElement;
11232 
11233  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11234  {
11235  Utilities->CallLogPop(126);
11236  return(false);
11237  }
11238 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11239  if(TrackElement.TrackType == Points)
11240  {
11241  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11242  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11243  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11244  //best to prevent it to avoid problems
11245  Utilities->CallLogPop(127);
11246  return false;
11247  }
11248 */
11249  TPrefDirElement PrefDirElement(TrackElement);
11250 
11251  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11252  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11253  StorePrefDirElement(1, PrefDirElement); // enter first element
11254 // Note that ELink not set even if a buffer or continuation - these set in
11255 // ConvertPrefDirSearchVector after 2nd element added
11256 
11257  Utilities->CallLogPop(128);
11258  return(true);
11259 }
11260 
11261 // ---------------------------------------------------------------------------
11262 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11263 
11264 /*
11265  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11266  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11267  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11268  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11269  so that the calling function knows that the PrefDir is complete.
11270  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11271  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11272  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11273  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11274  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11275  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11276  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11277  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11278 */
11279 
11280 {
11281  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11282  FinishElement = false;
11283  int TrackVectorPosition;
11284 
11285  TotalSearchCount = 0;
11286  TTrackElement TrackElement, TempTrackElement;
11287 
11288  if(PrefDirVector.size() == 0)
11289  {
11290  Utilities->CallLogPop(129);
11291  return(false);
11292  }
11293  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11294  {
11295  Utilities->CallLogPop(130);
11296  return(false);
11297  }
11298 // set the search limits using the last stored element in PrefDirVector as the start point
11299 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11300 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11301 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11302 
11303  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11304 
11305  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11306  {
11307  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11308  SearchLimitHighH = TrackElement.HLoc + 15;
11309  }
11310  else
11311  {
11312  SearchLimitLowH = TrackElement.HLoc - 15;
11313  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11314  }
11315  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11316  {
11317  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11318  SearchLimitHighV = TrackElement.VLoc + 15;
11319  }
11320  else
11321  {
11322  SearchLimitLowV = TrackElement.VLoc - 15;
11323  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11324  }
11325 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11326  check & TotalSearchCounts check
11327  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11328  {
11329  ShowMessage("Unable to reach the selected element - too far ahead");
11330  Utilities->CallLogPop(1692);
11331  return false;
11332  }
11333 */
11334 // get last PrefDir element
11335  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11336  {
11337  // check if TrackElement adjacent to any of the 4 XLinkPos'
11338  for(int x = 0; x < 4; x++)
11339  {
11340  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11341  {
11342  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11343  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11344  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11345  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11346  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11347  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11348  // shouldn't ever get it in a serious railway though.
11349 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11350  }
11351  }
11352  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11353  {
11354  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11355  SearchVector.clear(); // use this & convert to set all PrefDir element values
11356  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11357  {
11359  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11360  {
11361  FinishElement = true;
11362  }
11363  Utilities->CallLogPop(131);
11364  return(true);
11365  }
11366  } // not an adjacent element
11367 
11368  // now check each of the 4 possible XLinkPos values
11369  for(int x = 0; x < 4; x++)
11370  {
11371  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11372  {
11373  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11374  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11375  SearchVector.clear();
11376  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11377  {
11379  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11380  {
11381  FinishElement = true;
11382  }
11383  Utilities->CallLogPop(132);
11384  return(true);
11385  }
11386  }
11387  } // here if checked all possible exits without success
11388  ShowMessage(
11389  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11390  Utilities->CallLogPop(133);
11391  return(false);
11392  }
11393 // dealt above with LastPrefDirElement being the start element (which can be points)
11394 
11395  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11396  .ELinkPos] == Lead)) // leading point
11397  {
11398  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11399  {
11400  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11401  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11402  // can't be buffers or gap if points
11403  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11404  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11405  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11406  SearchVector.clear();
11407  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11408  {
11410  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11411  {
11412  FinishElement = true;
11413  }
11414  Utilities->CallLogPop(134);
11415  return(true);
11416  }
11417  }
11418  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11419  {
11420  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11421  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11422  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11423  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11424  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11425  SearchVector.clear();
11426  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11427  {
11429  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11430  {
11431  FinishElement = true;
11432  }
11433  Utilities->CallLogPop(135);
11434  return(true);
11435  }
11436  }
11437 // above dealt with immediate finds for leading point,
11438 // now deal with ordinary searches for leading point
11439  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11440  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11441  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11442  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11443  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11444  SearchVector.clear();
11445  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11446  {
11448  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11449  {
11450  FinishElement = true;
11451  }
11452  Utilities->CallLogPop(136);
11453  return(true);
11454  }
11455  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11456  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11457  // note that CheckCount already increased to allow for XLinkPos & XLink
11458  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11459  SearchVector.clear();
11460  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11461  {
11463  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11464  {
11465  FinishElement = true;
11466  }
11467  Utilities->CallLogPop(137);
11468  return(true);
11469  }
11470 // here if failed to find match for leading point
11471  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11472  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11473  ShowMessage(
11474  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11475  Utilities->CallLogPop(138);
11476  return(false);
11477  }
11478 // leading point fully dealt with above
11479 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11480 // separately as covered in ordinary search.
11481 
11482  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11483  SearchVector.clear();
11484 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11485  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11486  {
11488  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11489  {
11490  FinishElement = true;
11491  }
11492  Utilities->CallLogPop(139);
11493  return(true);
11494  }
11495  ShowMessage(
11496  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11497  Utilities->CallLogPop(140);
11498  return(false); // failed to find required element
11499 }
11500 
11501 // ---------------------------------------------------------------------------
11502 
11503 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11504 /*
11505  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11506  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11507  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11508  Keep a count of entries in SearchVector during the current function call, so that this number can be
11509  erased for an unproductive branch search.
11510  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11511  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11512  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11513  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11514  If not any of above, store element in searchvector, set the new current element values from the
11515  SearchElement, then go back to the while loop for the next step in the search.
11516 */
11517 {
11518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11519  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11520  int VectorCount = 0;
11521 
11522  while(true)
11523  {
11524  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11525  {
11526  for(int x = 0; x < VectorCount; x++)
11527  {
11528  SearchVector.erase(SearchVector.end() - 1);
11529  }
11530  Utilities->CallLogPop(141);
11531  return(false);
11532  }
11533  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11534  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11535  TPrefDirElement SearchElement(NextTrackElement);
11536  SearchElement.TrackVectorPosition = NextPosition;
11537  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11538  SearchElement.ELinkPos = NextELinkPos;
11539  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11540  int NextXLinkPos;
11541  if(SearchElement.ELinkPos == 0)
11542  {
11543  NextXLinkPos = 1;
11544  }
11545  if(SearchElement.ELinkPos == 1)
11546  {
11547  NextXLinkPos = 0;
11548  }
11549  if(SearchElement.ELinkPos == 2)
11550  {
11551  NextXLinkPos = 3;
11552  }
11553  if(SearchElement.ELinkPos == 3)
11554  {
11555  NextXLinkPos = 2;
11556  }
11557  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11558  {
11559  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11560  // but may be buffers, continuation or gap
11561  SearchElement.XLinkPos = NextXLinkPos;
11562  }
11563 // can't set XLink or XLinkPos yet if the element is a leading point.
11564 // check if found it
11565  if(SearchElement.TrackVectorPosition == RequiredPosition)
11566  {
11567  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11568  VectorCount++; // not really needed but include for tidyness
11569  TotalSearchCount++;
11570  Utilities->CallLogPop(142);
11571  return(true);
11572  }
11573 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11574 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11575 // at a time - drop this
11576 /*
11577  if(PrefDirVector.size() > 200)
11578  {
11579  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11580  Utilities->CallLogPop(1419);
11581  return false;
11582  }
11583 */
11584 // check if a buffer or continuation
11585  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11586  {
11587  for(int x = 0; x < VectorCount; x++)
11588  {
11589  SearchVector.erase(SearchVector.end() - 1);
11590  }
11591  Utilities->CallLogPop(143);
11592  return(false);
11593  }
11594 // check if reached an earlier position on search PrefDir with same entry value
11595  for(unsigned int x = 0; x < SearchVector.size(); x++)
11596  {
11597  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11598  {
11599  for(int x = 0; x < VectorCount; x++)
11600  {
11601  SearchVector.erase(SearchVector.end() - 1);
11602  }
11603  Utilities->CallLogPop(144);
11604  return(false);
11605  }
11606  }
11607 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11608 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11609  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11610  {
11611  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11612  {
11613  for(int x = 0; x < VectorCount; x++)
11614  {
11615  SearchVector.erase(SearchVector.end() - 1);
11616  }
11617  Utilities->CallLogPop(1417);
11618  return(false);
11619  }
11620  }
11621 
11622 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11623 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11624 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11626  {
11627  for(int x = 0; x < VectorCount; x++)
11628  {
11629  SearchVector.erase(SearchVector.end() - 1);
11630  }
11631  Utilities->CallLogPop(1691);
11632  return(false);
11633  }
11634 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11635  if(SearchVector.size() > 150)
11636  {
11637  for(int x = 0; x < VectorCount; x++)
11638  {
11639  SearchVector.erase(SearchVector.end() - 1);
11640  }
11641  Utilities->CallLogPop(1418);
11642  return(false);
11643  }
11644 // check if reached a leading point
11645  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11646  {
11647 // push element with XLink set to position [1]
11648  SearchElement.XLink = SearchElement.Link[1];
11649  SearchElement.XLinkPos = 1;
11650  SearchVector.push_back(SearchElement);
11651  VectorCount++;
11652  TotalSearchCount++;
11653  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11654  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11655  // can't be used. NextTrackElement is the corresponding TTrackElement.
11656  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11657  {
11658  Utilities->CallLogPop(145);
11659  return(true);
11660  }
11661  else
11662  {
11663 // remove leading point with XLinkPos [1]
11664  SearchVector.erase(SearchVector.end() - 1);
11665  VectorCount--;
11666 // push element with XLink set to position [3]
11667  SearchElement.XLink = SearchElement.Link[3];
11668  SearchElement.XLinkPos = 3;
11669  SearchVector.push_back(SearchElement);
11670  VectorCount++;
11671  TotalSearchCount++;
11672 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11673  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11674  {
11675  Utilities->CallLogPop(146);
11676  return(true);
11677  }
11678  else
11679  {
11680  for(int x = 0; x < VectorCount; x++)
11681  {
11682  SearchVector.erase(SearchVector.end() - 1);
11683  }
11684  Utilities->CallLogPop(147);
11685  return(false);
11686  }
11687  }
11688  } // if leading point
11689 
11690 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11691 // ready for next element on PrefDir
11692  SearchVector.push_back(SearchElement);
11693  VectorCount++;
11694  TotalSearchCount++;
11695  XLinkPos = NextXLinkPos;
11696  CurrentTrackElement = SearchElement;
11697  } // while(true)
11698 }
11699 
11700 // ---------------------------------------------------------------------------
11701 
11703 /*
11704  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11705  for each element on the search PrefDir, though if the last element is a leading point
11706  then the final XLink won't be set.
11707  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11708  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11709  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11710 */
11711 {
11712  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11713  if(SearchVector.size() == 0)
11714  {
11715  throw Exception("Error, SearchVector empty");
11716  }
11717 // get first SearchElement in order to set last PrefDirelement
11718  TPrefDirElement SearchElement = SearchVector.at(0);
11719 
11720 // set last PrefDir element XLink & ELink values if not already set
11721 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11722  for(int x = 0; x < 4; x++)
11723  {
11724  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11725  {
11726  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11727  {
11728  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
11729  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
11730  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
11731  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
11732  }
11733  int ELinkPos;
11734  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
11735  {
11736  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
11737  }
11738  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
11739  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
11740  {
11741  ELinkPos = 0;
11742  }
11743  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
11744  {
11745  ELinkPos = 3;
11746  }
11747  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
11748  {
11749  ELinkPos = 2;
11750  }
11751  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
11752  {
11753  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
11754  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
11755  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
11756  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
11757  }
11758  break; // no point going any further
11759  }
11760  }
11761 // set EXNumber for last PrefDir element, unless already set
11762 // won't be set if was first element or a leading point
11763  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
11764  {
11765 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
11766  int EXArray[32][2] = {
11767  {4,6},{2,8}, //horizontal & vertical
11768  {2,4},{6,2},{8,6},{4,8}, //sharp curves
11769  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
11770  {1,9},{3,7} //forward & reverse diagonals
11771 */
11772 
11773  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
11774  {
11775  throw Exception("Error in EntryExitNumber 1");
11776  }
11777  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
11778  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
11779  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
11780  }
11781 // Last PrefDir element now complete
11782 
11783 // construct remaining PrefDir elements from searchvector
11784  for(unsigned int x = 0; x < SearchVector.size(); x++)
11785  {
11786  SearchElement = SearchVector.at(x);
11787  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
11788  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
11789  PrefDirElement.ELink = SearchElement.ELink;
11790  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
11791  PrefDirElement.XLink = SearchElement.XLink;
11792  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
11793 // if XLink & XLinkPos not set don't account for them in CheckCount
11794  if(PrefDirElement.XLink == -1)
11795  {
11796  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11797  }
11798  // & TrackVectorPosition
11799  else
11800  {
11801  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11802  }
11803  // XLink, XLinkPos, TrackVectorPosition
11804 
11805 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
11806  if(PrefDirElement.XLink != -1)
11807  {
11808  if(!(PrefDirElement.EntryExitNumber()))
11809  {
11810  throw Exception("Error in EntryExitNumber 2");
11811  }
11812  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
11813  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
11814  PrefDirElement.CheckCount++;
11815  // all values now incorporated if not a leading point
11816  }
11817 // store PrefDir element
11818  StorePrefDirElement(2, PrefDirElement);
11819  }
11820 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
11821  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
11822  {
11823  if(ValidatePrefDir(2))
11824  {
11825  ;
11826  } // error messages given within function
11827 
11828  }
11830 /* drop this, check dropped from search
11831  if(PrefDirVector.size() > 200)
11832  {
11833  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
11834  }
11835 */
11836  Utilities->CallLogPop(148);
11837 }
11838 
11839 // ---------------------------------------------------------------------------
11840 
11841 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
11842 /*
11843  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
11844  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
11845 */
11846 {
11847  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
11848  LeadingPoints = false;
11849  if(PrefDirVector.empty())
11850  {
11851  Utilities->CallLogPop(1786);
11852  return(false); // should never be empty but allow for it for safety
11853  }
11854  if(PrefDirVector.size() == 1)
11855  {
11856  Utilities->CallLogPop(149);
11857  return(false); // can't end if only one element
11858  }
11859 /*
11860  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
11861  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
11862  {
11863  Utilities->CallLogPop(150);
11864  return true;
11865  }
11866 */
11867 // allow for anything but leading points
11868  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
11869  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
11870  {
11871  Utilities->CallLogPop(1776);
11872  return(true);
11873  }
11874  else
11875  {
11876  LeadingPoints = true;
11877  Utilities->CallLogPop(151);
11878  return(false);
11879  }
11880 }
11881 
11882 // ---------------------------------------------------------------------------
11883 
11885 /*
11886  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
11887  and that every element is connected to the next element
11888 */
11889 {
11890  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
11891  int Position;
11892  AnsiString ErrorString;
11893  bool Error = false;
11894 
11895  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11896  {
11897  if(PrefDirVector.at(x).HLoc == -2000000000)
11898  {
11899  Error = true;
11900  ErrorString = "HLoc";
11901  Position = x;
11902  }
11903  if(PrefDirVector.at(x).VLoc == -2000000000)
11904  {
11905  Error = true;
11906  ErrorString = "VLoc";
11907  Position = x;
11908  }
11909  if(PrefDirVector.at(x).ELink == -1)
11910  {
11911  Error = true;
11912  ErrorString = "ELink";
11913  Position = x;
11914  }
11915  if(PrefDirVector.at(x).ELinkPos == -1)
11916  {
11917  Error = true;
11918  ErrorString = "ELinkPos";
11919  Position = x;
11920  }
11921  if(PrefDirVector.at(x).XLink == -1)
11922  {
11923  Error = true;
11924  ErrorString = "XLink";
11925  Position = x;
11926  }
11927  if(PrefDirVector.at(x).XLinkPos == -1)
11928  {
11929  Error = true;
11930  ErrorString = "XLinkPos";
11931  Position = x;
11932  }
11933  if(PrefDirVector.at(x).SpeedTag == 0)
11934  {
11935  Error = true;
11936  ErrorString = "Tag";
11937  Position = x;
11938  }
11939  if(PrefDirVector.at(x).TrackVectorPosition == -1)
11940  {
11941  Error = true;
11942  ErrorString = "TrackVectorPosition";
11943  Position = x;
11944  }
11945  if(PrefDirVector.at(x).EXNumber == -1)
11946  {
11947  Error = true;
11948  ErrorString = "EXNumber";
11949  Position = x;
11950  }
11951  if(PrefDirVector.at(x).CheckCount != 9)
11952  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
11953  {
11954  Error = true;
11955  ErrorString = "CheckCount";
11956  Position = x;
11957  }
11958 // extra checks
11959  if(PrefDirVector.at(x).EXGraphicPtr == 0)
11960  {
11961  Error = true;
11962  ErrorString = "EntryGraphicPtr";
11963  Position = x;
11964  }
11965  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
11966  {
11967  Error = true;
11968  ErrorString = "EntryDirectionGraphicPtr";
11969  Position = x;
11970  }
11971 // end of extra checks
11972  if(x > 0)
11973  {
11974  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
11975  {
11976  Error = true;
11977  ErrorString = "Last XLink not connected to this element";
11978  Position = x;
11979  }
11980  }
11981  }
11982  if(Error)
11983  {
11984  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
11985  }
11986  else
11987  {
11988  Utilities->CallLogPop(153);
11989  return(true);
11990  }
11991 }
11992 
11993 // ---------------------------------------------------------------------------
11994 
11995 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
11996 /*
11997  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
11998  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
11999  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12000  or a leading point.
12001 */
12002 {
12003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12004  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12005  {
12006  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12007  {
12008  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12009  {
12010  ErasePrefDirElementAt(1, PrefDirVecPos);
12011  }
12012  if(PrefDirVector.size() == 0)
12013  {
12014  Utilities->CallLogPop(154);
12015  return(true);
12016  }
12017  if(PrefDirVector.size() == 1)
12018  {
12019  PrefDirVector.at(x - 1).ELinkPos = -1;
12020  PrefDirVector.at(x - 1).ELink = -1;
12021  PrefDirVector.at(x - 1).XLinkPos = -1;
12022  PrefDirVector.at(x - 1).XLink = -1;
12023  PrefDirVector.at(x - 1).EXNumber = -1;
12024  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12025  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12026  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12027  Utilities->CallLogPop(155);
12028  return(true);
12029  }
12030  // here with truncate element not first element, so ELink & ELinkPos set
12031  // unset XLink & Pos if a leading point
12032  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12033  {
12034  PrefDirVector.at(x - 1).XLinkPos = -1;
12035  PrefDirVector.at(x - 1).XLink = -1;
12036  PrefDirVector.at(x - 1).EXNumber = -1;
12037  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12038  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12039  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12040  Utilities->CallLogPop(156);
12041  return(true);
12042  }
12043  Utilities->CallLogPop(157);
12044  return(true);
12045  }
12046  }
12047  Utilities->CallLogPop(158);
12048  return(false);
12049 }
12050 
12051 // ---------------------------------------------------------------------------
12052 
12053 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12054 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12055 /*
12056  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12057  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12058  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12059  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12060  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12061  displayed.
12062 */
12063 {
12064  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12065  AnsiString((short)BuildingPrefDir));
12066  int HPos, VPos;
12067 
12068  if(PrefDirSize() == 0)
12069  {
12070  Utilities->CallLogPop(159);
12071  return;
12072  }
12073  for(unsigned int x = 0; x < PrefDirSize(); x++)
12074  {
12075  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12076 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12077 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12078 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12079  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12080  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12081  // only the front half of which will be overplotted by the back of the train, then when the train is
12082  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12083  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12084  {
12085  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12086  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12087  {
12088  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12089  }
12090  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12091  // Route, no direction if a single element
12092  {
12093  if(x == 0)
12094  {
12095  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12096  }
12097  if(x == (PrefDirSize() - 1))
12098  {
12099  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12100  }
12101  }
12102  }
12103  }
12104 
12105 // set start & end element colours if building a PrefDir
12106  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12107  {
12108  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12109  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12110  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12111  // set last element colour
12112  if(PrefDirSize() > 1)
12113  {
12114  unsigned int LatestPos = PrefDirSize() - 1;
12115  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12116  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12117  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12118  }
12119  }
12120  Disp->Update();
12121  Utilities->CallLogPop(160);
12122 }
12123 
12124 // ---------------------------------------------------------------------------
12125 
12127 /*
12128  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12129  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12130 */
12131 {
12132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12133  if(PrefDirSize() == 0)
12134  {
12135  Utilities->CallLogPop(1547);
12136  return;
12137  }
12138  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12139  bool FoundFlag;
12141  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12142 
12143  while(MMIT != PrefDir4MultiMap.end())
12144  {
12145  H = MMIT->first.first;
12146  V = MMIT->first.second;
12147  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12148  // always found in order, any missing have PrefDirPosx == -1
12149  if(PrefDirPos0 > -1)
12150  {
12151  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12152  }
12153  if(PrefDirPos1 > -1)
12154  {
12155  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12156  }
12157  if(PrefDirPos2 > -1)
12158  {
12159  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12160  }
12161  if(PrefDirPos3 > -1)
12162  {
12163  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12164  }
12165  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12166  {
12167  // need to plot all 4 in order to obtain all the direction graphics
12168  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12169  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12170  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12171  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12172  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12173  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12174  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12175  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12176  MMIT++;
12177  MMIT++;
12178  MMIT++;
12179  MMIT++;
12180  }
12181  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12182  {
12183  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12184  {
12185  // 0 & 1 constitute the bidirectional PrefDir
12186  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12187  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12188  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12189  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12190  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12191  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12192  MMIT++;
12193  MMIT++;
12194  MMIT++;
12195  }
12196  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12197  {
12198  // 0 & 2 constitute the bidirectional PrefDir
12199  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12200  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12201  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12202  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12203  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12204  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12205  MMIT++;
12206  MMIT++;
12207  MMIT++;
12208  }
12209  else
12210  {
12211  // 1 & 2 constitute the bidirectional PrefDir
12212  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12213  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12214  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12215  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12216  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12217  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12218  MMIT++;
12219  MMIT++;
12220  MMIT++;
12221  }
12222  }
12223  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12224  {
12225  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12226  {
12227  // 0 & 1 constitute the bidirectional PrefDir
12228  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12229  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12230  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12231  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12232  MMIT++;
12233  MMIT++;
12234  }
12235  else
12236  {
12237  // 2 unidirectional PrefDirs
12238  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12239  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12240  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12241  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12242  MMIT++;
12243  MMIT++;
12244  }
12245  }
12246  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12247  {
12248  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12249  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12250  MMIT++;
12251  }
12252  }
12253  Disp->Update();
12254  Utilities->CallLogPop(1548);
12255 }
12256 
12257 // ---------------------------------------------------------------------------
12258 
12259 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12260 {
12261  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12262  int TempInt;
12263 
12264  ClearPrefDir();
12265  int NumberOfPrefDirElements = 0;
12266 
12267  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12268  for(int x = 0; x < NumberOfPrefDirElements; x++)
12269  {
12270  VecFile >> TempInt; // TrackVectorPosition
12271  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12272  LoadPrefDirElement.TrackVectorPosition = TempInt;
12273  VecFile >> TempInt;
12274  LoadPrefDirElement.ELink = TempInt;
12275  VecFile >> TempInt;
12276  LoadPrefDirElement.ELinkPos = TempInt;
12277  VecFile >> TempInt;
12278  LoadPrefDirElement.XLink = TempInt;
12279  VecFile >> TempInt;
12280  LoadPrefDirElement.XLinkPos = TempInt;
12281  VecFile >> TempInt;
12282  LoadPrefDirElement.EXNumber = TempInt;
12283  VecFile >> TempInt;
12284  LoadPrefDirElement.CheckCount = TempInt;
12285  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12286  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12287  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12288  if(!(LoadPrefDirElement.IsARoute))
12289  {
12290  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12291  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12292  }
12293  else
12294  {
12295  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12296  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12297  LoadPrefDirElement.PrefDirRoute);
12298  }
12299  StorePrefDirElement(5, LoadPrefDirElement);
12300  Utilities->LoadFileString(VecFile); // marker
12301  }
12303  Utilities->CallLogPop(161);
12304 }
12305 
12306 // ---------------------------------------------------------------------------
12307 
12308 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12309 {
12310  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12311  int TempInt;
12312 
12313  ClearPrefDir();
12314  int NumberOfPrefDirElements = 0;
12315 
12316  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12317  for(int x = 0; x < NumberOfPrefDirElements; x++)
12318  {
12319  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12320  VecFile >> TempInt; // TrackVectorPosition
12321  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt));
12322  LoadPrefDirElement.TrackVectorPosition = TempInt;
12323  VecFile >> TempInt;
12324  LoadPrefDirElement.ELink = TempInt;
12325  VecFile >> TempInt;
12326  LoadPrefDirElement.ELinkPos = TempInt;
12327  VecFile >> TempInt;
12328  LoadPrefDirElement.XLink = TempInt;
12329  VecFile >> TempInt;
12330  LoadPrefDirElement.XLinkPos = TempInt;
12331  VecFile >> TempInt;
12332  LoadPrefDirElement.EXNumber = TempInt;
12333  VecFile >> TempInt;
12334  LoadPrefDirElement.CheckCount = TempInt;
12335  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12336  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12337  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12338  if(!(LoadPrefDirElement.IsARoute))
12339  {
12340  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12341  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12342  }
12343  else
12344  {
12345  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12346  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12347  LoadPrefDirElement.PrefDirRoute);
12348  }
12349  StorePrefDirElement(0, LoadPrefDirElement);
12350  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12351  }
12353  Utilities->CallLogPop(1509);
12354 }
12355 
12356 // ---------------------------------------------------------------------------
12357 
12358 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12359 /*
12360  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12361  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12362 */
12363 {
12364  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12365  int TempInt;
12366  int NumberOfPrefDirElements = 0;
12367 
12368  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12369  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12370  {
12371  Utilities->CallLogPop(1152);
12372  return(false);
12373  }
12374  for(int x = 0; x < NumberOfPrefDirElements; x++)
12375  {
12376  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12377  {
12378  Utilities->CallLogPop(1766);
12379  return(false);
12380  }
12381  VecFile >> TempInt;
12382  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12383  {
12384  Utilities->CallLogPop(163);
12385  return(false);
12386  }
12387  VecFile >> TempInt;
12388  if((TempInt < -1) || (TempInt > 9)) // ELink
12389  {
12390  Utilities->CallLogPop(162);
12391  return(false);
12392  }
12393  VecFile >> TempInt;
12394  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12395  {
12396  Utilities->CallLogPop(164);
12397  return(false);
12398  }
12399  VecFile >> TempInt;
12400  if((TempInt < -1) || (TempInt > 9)) // XLink
12401  {
12402  Utilities->CallLogPop(165);
12403  return(false);
12404  }
12405  VecFile >> TempInt;
12406  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12407  {
12408  Utilities->CallLogPop(166);
12409  return(false);
12410  }
12411  VecFile >> TempInt;
12412  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12413  {
12414  Utilities->CallLogPop(167);
12415  return(false);
12416  }
12417  VecFile >> TempInt;
12418  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12419  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12420  // ELinkPos, XLink, XLinkPos & EXNumber
12421  {
12422  Utilities->CallLogPop(168);
12423  return(false);
12424  }
12425  VecFile >> TempInt;
12426  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12427  {
12428  Utilities->CallLogPop(1147);
12429  return(false);
12430  }
12431  VecFile >> TempInt;
12432  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12433  {
12434  Utilities->CallLogPop(1510);
12435  return(false);
12436  }
12437  VecFile >> TempInt;
12438  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12439  {
12440  Utilities->CallLogPop(1148);
12441  return(false);
12442  }
12443  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12444  {
12445  Utilities->CallLogPop(1700);
12446  return(false);
12447  }
12448  }
12449  Utilities->CallLogPop(169);
12450  return(true);
12451 }
12452 
12453 // ---------------------------------------------------------------------------
12454 
12455 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12456 {
12457  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12458  int NumberOfPrefDirElements = PrefDirVector.size();
12459 
12460  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12461  for(int y = 0; y < NumberOfPrefDirElements; y++)
12462  {
12463  VecFile << y << '\n'; // extra
12464  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n';
12465  VecFile << PrefDirVector.at(y).ELink << '\n';
12466  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12467  VecFile << PrefDirVector.at(y).XLink << '\n';
12468  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12469  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12470  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12471  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12472  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12473  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12474  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12475  {
12476  VecFile << "************" << '\0' << '\n'; // marker
12477  }
12478  else
12479  {
12480  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12481  }
12482  }
12483  Utilities->CallLogPop(170);
12484 }
12485 
12486 // ---------------------------------------------------------------------------
12487 
12488 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12489 {
12490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12491  int NumberOfSearchElements = SearchVector.size();
12492 
12493  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12494  for(int y = 0; y < NumberOfSearchElements; y++)
12495  {
12496  VecFile << y << '\n'; // extra
12497  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12498  VecFile << SearchVector.at(y).ELink << '\n';
12499  VecFile << SearchVector.at(y).ELinkPos << '\n';
12500  VecFile << SearchVector.at(y).XLink << '\n';
12501  VecFile << SearchVector.at(y).XLinkPos << '\n';
12502  VecFile << SearchVector.at(y).EXNumber << '\n';
12503  VecFile << SearchVector.at(y).CheckCount << '\n';
12504  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12505  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12506  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12507  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12508  {
12509  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12510  }
12511  else
12512  {
12513  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12514  }
12515  }
12516  Utilities->CallLogPop(1847);
12517 }
12518 
12519 // ---------------------------------------------------------------------------
12520 
12521 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12522 /*
12523  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12524  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12525 */
12526 {
12527  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12528  AnsiString(VLoc));
12529  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12530 
12531  if(VecPos > -1)
12532  {
12533  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12534  }
12535  else
12536  {
12537  Utilities->CallLogPop(171);
12538  return;
12539  }
12540  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12541  if(VecPos > -1)
12542  {
12543  ErasePrefDirElementAt(3, VecPos);
12544  }
12545  else
12546  {
12547  Utilities->CallLogPop(172);
12548  return;
12549  }
12550  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12551  if(VecPos > -1)
12552  {
12553  ErasePrefDirElementAt(4, VecPos);
12554  }
12555  else
12556  {
12557  Utilities->CallLogPop(173);
12558  return;
12559  }
12560  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12561  if(VecPos > -1)
12562  {
12563  ErasePrefDirElementAt(5, VecPos);
12564  }
12565  else
12566  {
12567  Utilities->CallLogPop(174);
12568  return;
12569  }
12570  Utilities->CallLogPop(175);
12571 }
12572 
12573 // ---------------------------------------------------------------------------
12574 /*
12575  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12576  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12577 
12578  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12579  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12580  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12581  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12582  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12583  PrefDirVector to correspond to the new track layout.
12584 
12585  {
12586  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12587  if(PrefDirSize() == 0)
12588  {
12589  Utilities->CallLogPop(176);
12590  return;
12591  }
12592  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12593  {
12594  int TV = PrefDirVector.at(x).TrackVectorPosition;
12595  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12596  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12597  if(Track->BlankElementAt(0, TV))
12598  {
12599  ErasePrefDirElementAt(6, x);
12600  }
12601  //if was a blankelement at x then ConnELink and ConnXLink both -1
12602  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12603  {
12604  ErasePrefDirElementAt(7, x);
12605  }
12606  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12607  //needs to be erased once, but if don't use 'else' then will erase two elements
12608  //since 'x' will correspond to the element after the first erased element
12609  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12610  {
12611  ErasePrefDirElementAt(8, x);
12612  }
12613  }
12614  Utilities->CallLogPop(177);
12615  }
12616 */
12617 // ---------------------------------------------------------------------------
12618 
12619 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12620 /*
12621  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12622  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12623 */
12624 {
12625  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12626  bool AlreadyPresent, FoundFlag;
12627  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12628 
12629  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12630  {
12631  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12632  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12633  AlreadyPresent = false;
12634  if(FoundFlag)
12635  {
12636  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12637  {
12638  AlreadyPresent = true;
12639  }
12640  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12641  {
12642  AlreadyPresent = true;
12643  }
12644  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12645  {
12646  AlreadyPresent = true;
12647  }
12648  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12649  {
12650  AlreadyPresent = true;
12651  }
12652  }
12653  if(!AlreadyPresent)
12654  {
12655  StorePrefDirElement(4, TempElement);
12656  }
12657  }
12659  Utilities->CallLogPop(178);
12660 }
12661 /* earlier brute force search
12662  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12663  {
12664  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12665  bool AlreadyPresent = false;
12666  for(unsigned int y = 0;y<PrefDirSize();y++)
12667  {
12668  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12669  }
12670  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12671  }
12672 */
12673 
12674 // ---------------------------------------------------------------------------
12675 
12677 /*
12678  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12679  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12680  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12681  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12682  positions are likely to have changed, so this function is called to reset all the necessary connections and
12683  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12684  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12685  shouldn't have changed.
12686 */
12687 {
12688  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12689  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12690  {
12691  bool FoundFlag;
12692  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12693  if(FoundFlag)
12694  {
12695  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12696  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12697  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12698  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12699  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12700  for(unsigned int z = 0; z < 4; z++)
12701  {
12702  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12703  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12704  }
12705  }
12706  else
12707  {
12708  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12709  }
12710  }
12711  Utilities->CallLogPop(179);
12712 }
12713 
12714 // ---------------------------------------------------------------------------
12715 
12717 /*
12718  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12719 */
12720 {
12721  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12722  bool DiscrepancyFound = false;
12723 
12724  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12725  {
12726  bool FoundFlag;
12727  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12728  if(FoundFlag)
12729  {
12730  TPrefDirElement PE = PrefDirVector.at(x);
12731  if(PE.TrackVectorPosition != VecPos)
12732  {
12733  DiscrepancyFound = true;
12734  }
12735  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12736  {
12737  DiscrepancyFound = true;
12738  break;
12739  }
12740  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12741  {
12742  DiscrepancyFound = true;
12743  break;
12744  }
12745  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
12746  {
12747  DiscrepancyFound = true;
12748  break;
12749  }
12750  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
12751  {
12752  DiscrepancyFound = true;
12753  break;
12754  }
12755  }
12756  else
12757  {
12758  DiscrepancyFound = true;
12759  }
12760  }
12761  if(DiscrepancyFound)
12762  {
12763  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
12764  ClearPrefDir(); // also clears multimap
12765  }
12766  Utilities->CallLogPop(1436);
12767 }
12768 
12769 // ---------------------------------------------------------------------------
12770 
12772 /*
12773  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
12774  return true for OK
12775 */
12776 {
12777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
12778  bool DiscrepancyFound = false;
12779 
12780  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12781  {
12782  bool FoundFlag;
12783  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12784  if(FoundFlag)
12785  {
12786  TPrefDirElement PE = PrefDirVector.at(x);
12787  if(PE.TrackVectorPosition != VecPos)
12788  {
12789  DiscrepancyFound = true;
12790  }
12791  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12792  {
12793  DiscrepancyFound = true;
12794  break;
12795  }
12796  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12797  {
12798  DiscrepancyFound = true;
12799  break;
12800  }
12801  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
12802  {
12803  DiscrepancyFound = true;
12804  break;
12805  }
12806  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
12807  {
12808  DiscrepancyFound = true;
12809  break;
12810  }
12811  }
12812  else
12813  {
12814  DiscrepancyFound = true;
12815  }
12816  }
12817  Utilities->CallLogPop(1512);
12818  return(!DiscrepancyFound);
12819 }
12820 
12821 // ---------------------------------------------------------------------------
12822 
12823 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
12824 /*
12825  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
12826  turn and for the overall sizes.
12827 */
12828 {
12829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
12830  bool FoundFlag = false;
12831  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
12832 
12833  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
12834  {
12835  TPrefDirElement CheckElement = PrefDirVector.at(a);
12836  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
12837  if(!FoundFlag)
12838  {
12839  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
12840  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
12841  }
12842  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
12843  {
12844  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
12845  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
12846  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
12847  }
12848  }
12849  if(PrefDirVector.size() != PrefDir4MultiMap.size())
12850  {
12851  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
12852  + " Caller=" + (AnsiString)Caller);
12853  }
12854  Utilities->CallLogPop(180);
12855 }
12856 
12857 // ---------------------------------------------------------------------------
12858 
12859 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
12860  int &PrefDirPos3)
12861 /*
12862  There are up to four elements at each H & V position in the PrefDirVector - two directions, and up to
12863  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
12864  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
12865  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
12866  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
12867 */
12868 {
12869  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
12870  AnsiString(VLoc));
12871  THVPair PrefDirMapKeyPair;
12872 
12873  PrefDirPos0 = -1;
12874  PrefDirPos1 = -1;
12875  PrefDirPos2 = -1;
12876  PrefDirPos3 = -1;
12877  FoundFlag = false;
12878  PrefDirMapKeyPair.first = HLoc;
12879  PrefDirMapKeyPair.second = VLoc;
12880  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
12881 
12882  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
12883  if(ItPair.first == ItPair.second)
12884  {
12885  Utilities->CallLogPop(181);
12886  return;
12887  }
12888  else
12889  {
12890  FoundFlag = true;
12891  PrefDirPos0 = ItPair.first->second;
12892  ItPair.first++;
12893  if(ItPair.first == ItPair.second)
12894  {
12895  Utilities->CallLogPop(182);
12896  return;
12897  }
12898  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12899  {
12900  PrefDirPos1 = ItPair.first->second;
12901  }
12902  ItPair.first++;
12903  if(ItPair.first == ItPair.second)
12904  {
12905  Utilities->CallLogPop(183);
12906  return;
12907  }
12908  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12909  {
12910  PrefDirPos2 = ItPair.first->second;
12911  }
12912  ItPair.first++;
12913  if(ItPair.first == ItPair.second)
12914  {
12915  Utilities->CallLogPop(184);
12916  return;
12917  }
12918  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
12919  {
12920  PrefDirPos3 = ItPair.first->second;
12921  }
12922  }
12923  Utilities->CallLogPop(185);
12924 }
12925 
12926 // ---------------------------------------------------------------------------
12927 
12928 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
12929 /*
12930  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
12931 */
12932 {
12933  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
12934  PrefDirVector.push_back(LoadPrefDirElement);
12935  THVPair PrefDir4MultiMapKeyPair;
12936  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
12937 
12938  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
12939  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
12940  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
12941  PrefDir4MultiMapEntry.second = LastElementNumber(68);
12942  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
12943 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
12944  Utilities->CallLogPop(186);
12945 }
12946 
12947 // ---------------------------------------------------------------------------
12948 
12949 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
12950 /*
12951  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
12952  4MultiMap if they are greater than the erased value.
12953 */
12954 {
12955  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
12956  bool FoundFlag;
12957 
12958  if(!PrefDirVector.empty())
12959  {
12960  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
12961  if(!FoundFlag)
12962  {
12963  throw Exception("Failed to find PrefDir4MultiMap erase element");
12964  }
12965  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
12966  PrefDir4MultiMap.erase(EraseIt);
12967  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
12969  }
12970  Utilities->CallLogPop(187);
12971 }
12972 
12973 // ---------------------------------------------------------------------------
12974 
12975 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
12976 /*
12977  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
12978  4MultiMap if they are greater than the erased value.
12979 */
12980 {
12981  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
12982  AnsiString(ErasedElementNumber));
12983  if(!PrefDir4MultiMap.empty())
12984  {
12985  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
12986  {
12987  if(MapPtr->second > ErasedElementNumber)
12988  {
12989  MapPtr->second--;
12990  }
12991  }
12992  }
12993  Utilities->CallLogPop(1450);
12994 }
12995 
12996 // ---------------------------------------------------------------------------
12997 
12998 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
12999 /*
13000  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13001  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13002  nothing is found this is an error but the error message is given in the calling function.
13003 */
13004 {
13005  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13006  FoundFlag = false;
13007  if(PrefDirVectorPosition >= PrefDirVector.size())
13008  {
13009  throw Exception("PrefDirVectorPosition out of range");
13010  }
13011  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13012  THVPair PrefDir4MultiMapKeyPair;
13013 
13014  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13015  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13016  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13017 
13018  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13019  if(ItPair.first == ItPair.second)
13020  {
13021  Utilities->CallLogPop(188);
13022  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13023  }
13024  else
13025  {
13026  if(ItPair.first->second == PrefDirVectorPosition)
13027  {
13028  FoundFlag = true;
13029  Utilities->CallLogPop(189);
13030  return(ItPair.first);
13031  }
13032  ItPair.first++;
13033  if(ItPair.first == ItPair.second)
13034  {
13035  Utilities->CallLogPop(190);
13036  return(ItPair.first); // nothing found
13037  }
13038  if(ItPair.first->second == PrefDirVectorPosition)
13039  {
13040  FoundFlag = true;
13041  Utilities->CallLogPop(191);
13042  return(ItPair.first);
13043  }
13044  ItPair.first++;
13045  if(ItPair.first == ItPair.second)
13046  {
13047  Utilities->CallLogPop(192);
13048  return(ItPair.first); // nothing found
13049  }
13050  if(ItPair.first->second == PrefDirVectorPosition)
13051  {
13052  FoundFlag = true;
13053  Utilities->CallLogPop(193);
13054  return(ItPair.first);
13055  }
13056  ItPair.first++;
13057  if(ItPair.first == ItPair.second)
13058  {
13059  Utilities->CallLogPop(194);
13060  return(ItPair.first); // nothing found
13061  }
13062  if(ItPair.first->second == PrefDirVectorPosition)
13063  {
13064  FoundFlag = true;
13065  Utilities->CallLogPop(195);
13066  return(ItPair.first);
13067  }
13068  }
13069  Utilities->CallLogPop(196);
13070  return(ItPair.first); // nothing found
13071 }
13072 
13073 // ---------------------------------------------------------------------------
13074 
13075 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13076 /*
13077  Although there may be up to four entries at one H & V position this function gets just one. It is
13078  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13079  at H & V.
13080 */
13081 {
13082  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13083  THVPair PrefDir4MultiMapKeyPair;
13084 
13085  PrefDir4MultiMapKeyPair.first = HLoc;
13086  PrefDir4MultiMapKeyPair.second = VLoc;
13087  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13088 
13089  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13090  if(ItPair.first == ItPair.second) // nothing found
13091  {
13092  Utilities->CallLogPop(197);
13093  return(-1);
13094  }
13095  else
13096  {
13097  Utilities->CallLogPop(198);
13098  return(ItPair.first->second);
13099  }
13100 }
13101 
13102 // ---------------------------------------------------------------------------
13103 
13104 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13105 {
13106  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13107  bool ErasedFlag = false;
13108 
13109  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13110  {
13111  if(PrefDirSize() == 0)
13112  {
13113  Utilities->CallLogPop(1511);
13114  return;
13115  }
13116  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13117  {
13118  ErasedFlag = false;
13119  // use 'else' to ensure don't try to access an erased element
13120  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13121  {
13122  ErasePrefDirElementAt(11, x);
13123  ErasedFlag = true;
13124  }
13125  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13126  {
13127  ErasePrefDirElementAt(12, x);
13128  ErasedFlag = true;
13129  }
13130  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13131  {
13132  ErasePrefDirElementAt(13, x);
13133  ErasedFlag = true;
13134  }
13135  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13136  {
13137  ErasePrefDirElementAt(9, x);
13138  ErasedFlag = true;
13139  }
13140  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13141  {
13142  ErasePrefDirElementAt(10, x);
13143  ErasedFlag = true;
13144  }
13145  if(!ErasedFlag)
13146  {
13147  // don't use 'else' here as may be more than one that need decrementing
13148  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13149  {
13150  PrefDirVector.at(x).TrackVectorPosition--;
13151  }
13152  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13153  {
13154  PrefDirVector.at(x).Conn[0]--;
13155  }
13156  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13157  {
13158  PrefDirVector.at(x).Conn[1]--;
13159  }
13160  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13161  {
13162  PrefDirVector.at(x).Conn[2]--;
13163  }
13164  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13165  {
13166  PrefDirVector.at(x).Conn[3]--;
13167  }
13168  }
13169  }
13170  }
13171  Utilities->CallLogPop(1434);
13172 }
13173 
13174 // ---------------------------------------------------------------------------
13175 
13176 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13177 {
13178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13179  OverallDistance = 0;
13180  OverallSpeedLimit = 0;
13181  LeadingPointsAtLastElement = false;
13182  if(PrefDirSize() == 0) // shouldn't be empty when this called
13183  {
13184  Utilities->CallLogPop(1491);
13185  return;
13186  }
13187  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13188  {
13189  LeadingPointsAtLastElement = true;
13190  Utilities->CallLogPop(1492);
13191  return;
13192  }
13193  for(unsigned int x = 0; x < PrefDirSize(); x++)
13194  {
13195  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13196  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13197  {
13198  OverallDistance += PrefDirElement.Length23;
13199  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13200  {
13201  if(x == 0)
13202  {
13203  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13204  }
13205  else
13206  {
13207  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13208  {
13209  OverallSpeedLimit = -1;
13210  }
13211  }
13212  }
13213  }
13214  else
13215  {
13216  OverallDistance += PrefDirElement.Length01;
13217  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13218  {
13219  if(x == 0)
13220  {
13221  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13222  }
13223  else
13224  {
13225  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13226  {
13227  OverallSpeedLimit = -1;
13228  }
13229  }
13230  }
13231  }
13232  }
13233  Utilities->CallLogPop(1529);
13234 }
13235 
13236 // ---------------------------------------------------------------------------
13237 
13238 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13239 {
13240  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13241  if(PrefDirSize() == 0)
13242  {
13243  Utilities->CallLogPop(1564);
13244  return;
13245  }
13246  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13247  bool FoundFlag;
13249  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13250 
13251  while(MMIT != PrefDir4MultiMap.end())
13252  {
13253  HLoc = MMIT->first.first;
13254  VLoc = MMIT->first.second;
13255  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13256  H = HLoc - Track->GetHLocMin();
13257  V = VLoc - Track->GetVLocMin();
13258  // always found in order, any missing have PrefDirPosx == -1
13259  if(PrefDirPos0 > -1)
13260  {
13261  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13262  }
13263  if(PrefDirPos1 > -1)
13264  {
13265  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13266  }
13267  if(PrefDirPos2 > -1)
13268  {
13269  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13270  }
13271  if(PrefDirPos3 > -1)
13272  {
13273  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13274  }
13275  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13276  {
13277  // need to plot all 4 in order to obtain all the direction graphics
13278  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13279  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13280  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13281  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13282  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13283  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13284  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13285  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13286  MMIT++;
13287  MMIT++;
13288  MMIT++;
13289  MMIT++;
13290  }
13291  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13292  {
13293  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13294  {
13295  // 0 & 1 constitute the bidirectional PrefDir
13296  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13297  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13298  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13299  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13300  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13301  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13302  MMIT++;
13303  MMIT++;
13304  MMIT++;
13305  }
13306  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13307  {
13308  // 0 & 2 constitute the bidirectional PrefDir
13309  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13310  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13311  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13312  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13313  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13314  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13315  MMIT++;
13316  MMIT++;
13317  MMIT++;
13318  }
13319  else
13320  {
13321  // 1 & 2 constitute the bidirectional PrefDir
13322  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13323  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13324  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13325  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13326  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13327  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13328  MMIT++;
13329  MMIT++;
13330  MMIT++;
13331  }
13332  }
13333  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13334  {
13335  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13336  {
13337  // 0 & 1 constitute the bidirectional PrefDir
13338  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13339  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13340  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13341  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13342  MMIT++;
13343  MMIT++;
13344  }
13345  else
13346  {
13347  // 2 unidirectional PrefDirs
13348  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13349  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13350  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13351  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13352  MMIT++;
13353  MMIT++;
13354  }
13355  }
13356  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13357  {
13358  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13359  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13360  MMIT++;
13361  }
13362  }
13363  Utilities->CallLogPop(1565);
13364 }
13365 
13366 // ---------------------------------------------------------------------------
13367 
13368 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13369 /*
13370  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13371  level crossing, signals with wrong direction set, or buffers.
13372 */
13373 {
13374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13375  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13376  bool FoundFlag;
13378  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13379 
13380  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13381  ElementIn.VLoc)))
13382  {
13383  Utilities->CallLogPop(1982);
13384  return(false);
13385  }
13386  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13387  {
13388  Utilities->CallLogPop(1983);
13389  return(false);
13390  }
13391  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13392  {
13393  Utilities->CallLogPop(1995);
13394  return(false);
13395  }
13396 // Now check that there is only a single prefdir set
13397  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13398 // always found in order, any missing have PrefDirPosx == -1
13399  if(PrefDirPos0 > -1)
13400  {
13401  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13402  }
13403  if(PrefDirPos1 > -1)
13404  {
13405  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13406  }
13407  if(PrefDirPos2 > -1)
13408  {
13409  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13410  }
13411  if(PrefDirPos3 > -1)
13412  {
13413  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13414  }
13415  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13416  {
13417  Utilities->CallLogPop(1984);
13418  return(false);
13419  }
13420  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13421  {
13422  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13423  {
13424  Utilities->CallLogPop(1985);
13425  return(false);
13426  }
13427  else
13428  {
13429  Utilities->CallLogPop(1986);
13430  return(true);
13431  }
13432  }
13433  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13434  {
13435  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13436  {
13437  Utilities->CallLogPop(1987);
13438  return(false);
13439  }
13440  else
13441  {
13442  Utilities->CallLogPop(1988);
13443  return(true);
13444  }
13445  }
13446  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13447  {
13448  if(PrefDirElement0.XLinkPos == EntryPos)
13449  {
13450  Utilities->CallLogPop(1989);
13451  return(false);
13452  }
13453  else
13454  {
13455  Utilities->CallLogPop(1990);
13456  return(true);
13457  }
13458  }
13459  else
13460  {
13461  Utilities->CallLogPop(1991);
13462  return(false); // none found
13463  }
13464 }
13465 
13466 // ---------------------------------------------------------------------------
13467 
13469 {
13470 /* //Added at v2.1.0
13471  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13472  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13473  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13474  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13475  and can be modelled better anyway.
13476 
13477  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
13478  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
13479  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13480  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13481  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13482  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13483 */
13484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
13485  ElementIn.VLoc + "," + XLink);
13486  int TrackVecPos;
13487  bool TrackFoundFlag;
13488  TTrackElement TempTrackElement;
13489 
13490  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
13491  {
13492  Utilities->CallLogPop(2047);
13493  return(false);
13494  }
13495 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13496  if(XLink == 1)
13497  {
13498  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13499  if(TrackFoundFlag)
13500  {
13501  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
13502  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13503  {
13504  Utilities->CallLogPop(2048);
13505  return(true);
13506  }
13507  }
13508  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13509  if(TrackFoundFlag)
13510  {
13511  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
13512  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13513  {
13514  Utilities->CallLogPop(2049);
13515  return(true);
13516  }
13517  }
13518  }
13519 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13520  if(XLink == 3)
13521  {
13522  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13523  if(TrackFoundFlag)
13524  {
13525  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
13526  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13527  {
13528  Utilities->CallLogPop(2050);
13529  return(true);
13530  }
13531  }
13532  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13533  if(TrackFoundFlag)
13534  {
13535  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
13536  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13537  {
13538  Utilities->CallLogPop(2051);
13539  return(true);
13540  }
13541  }
13542  }
13543 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13544  if(XLink == 7)
13545  {
13546  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13547  if(TrackFoundFlag)
13548  {
13549  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
13550  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13551  {
13552  Utilities->CallLogPop(2052);
13553  return(true);
13554  }
13555  }
13556  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13557  if(TrackFoundFlag)
13558  {
13559  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
13560  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13561  {
13562  Utilities->CallLogPop(2053);
13563  return(true);
13564  }
13565  }
13566  }
13567 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13568  if(XLink == 9)
13569  {
13570  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13571  if(TrackFoundFlag)
13572  {
13573  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
13574  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13575  {
13576  Utilities->CallLogPop(2054);
13577  return(true);
13578  }
13579  }
13580  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13581  if(TrackFoundFlag)
13582  {
13583  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
13584  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13585  {
13586  Utilities->CallLogPop(2055);
13587  return(true);
13588  }
13589  }
13590  }
13591  Utilities->CallLogPop(2056);
13592  return(false);
13593 }
13594 
13595 // ---------------------------------------------------------------------------
13596 
13597 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
13598 {
13599 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
13600  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
13601  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
13602  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
13603  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
13604 */
13605  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
13607  bool FoundFlag, ContFlag, FoundElements = false;
13608  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13609  TPrefDirElement NextElement;
13610 
13611  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
13612  {
13613  LastIteratorValue++;
13614  ContFlag = false;
13615  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
13616  {
13617  continue;
13618  }
13619  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
13620  {
13621  continue;
13622  }
13623 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
13624  // found a potential route start point
13625  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
13626  {
13627  continue;
13628  }
13629  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
13630  {
13631  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
13632  if(PDVIt->TrackType == Continuation)
13633  {
13634  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
13635  {
13636  continue;
13637  }
13638  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
13639  {
13640  continue;
13641  }
13642  }
13643  StartElement = *PDVIt;
13644 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
13645  // diverging track on which there was no pref dir. See below for 2 required changes.
13646  }
13647  else
13648  {
13649  continue;
13650  }
13651  // now track along until find a signal or continuation, checking validity for each element
13652  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
13653  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
13654  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13655  if(PrefDirPos0 == -1) // no continuing prefdir
13656  {
13657  continue;
13658  }
13659  bool NextElementFoundFlag = false;
13660  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13661  {
13662  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
13663  NextElementFoundFlag = true;
13664  }
13665  if(PrefDirPos1 > -1)
13666  {
13667  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13668  {
13669  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
13670  NextElementFoundFlag = true;
13671  }
13672  }
13673  if(PrefDirPos2 > -1)
13674  {
13675  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13676  {
13677  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
13678  NextElementFoundFlag = true;
13679  }
13680  }
13681  if(PrefDirPos3 > -1)
13682  {
13683  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13684  {
13685  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
13686  NextElementFoundFlag = true;
13687  }
13688  }
13689  if(!NextElementFoundFlag)
13690  {
13691  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
13692 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
13693  }
13694  while(true)
13695  {
13696  // check validity
13697  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
13698  {
13699  ContFlag = true;
13700  break;
13701  }
13702  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
13703  {
13704  ContFlag = true;
13705  break;
13706  }
13707  // check if in a route, providing not a signal, as a signal might be at the start of a route
13708  if(NextElement.TrackType != SignalPost)
13709  {
13710  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
13711  {
13712  ContFlag = true;
13713  break;
13714  }
13715  }
13716  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
13717  // can't be a gound signal as would have failed the validity test
13718  {
13719  EndElement = NextElement;
13720  break;
13721  }
13722  // get the next element in the sequence
13723  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
13724  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
13725  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13726  if(PrefDirPos0 == -1) // no continuing prefdir
13727  {
13728  ContFlag = true;
13729  break;
13730  }
13731  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13732  {
13733  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
13734  continue;
13735  }
13736  if(PrefDirPos1 > -1)
13737  {
13738  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13739  {
13740  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
13741  continue;
13742  }
13743  }
13744  if(PrefDirPos2 > -1)
13745  {
13746  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13747  {
13748  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
13749  continue;
13750  }
13751  }
13752  if(PrefDirPos3 > -1)
13753  {
13754  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
13755  {
13756  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
13757  continue;
13758  }
13759  }
13760  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
13761  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
13762  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
13763  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
13764  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
13765  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
13766  {
13767  ContFlag = true;
13768  break;
13769  }
13770  else
13771  {
13772  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
13773  // could drop the bridge test but keep it to show the change history
13774  break;
13775 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
13776  }
13777  }
13778  if(ContFlag)
13779  {
13780  continue;
13781  }
13782  // else have start and end elements set & all elements valid, so set up the route segment
13783  FoundElements = true;
13784  break;
13785  }
13786  if(FoundElements)
13787  {
13788  Utilities->CallLogPop(1992);
13789  return(true);
13790  }
13791  else
13792  {
13793  Utilities->CallLogPop(1993);
13794  return(false);
13795  }
13796 }
13797 
13798 // ---------------------------------------------------------------------------
13799 // TOneRoute
13800 // ---------------------------------------------------------------------------
13801 
13802 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
13803 {
13804 /* General:
13805  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
13806  containing all the new elements to form the route. When complete, the SearchVector is converted into route
13807  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
13808  route will use automatic signals or not.
13809  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
13810  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
13811  elements, so additional work is needed to complete all their members before they are ready for conversion into
13812  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
13813  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
13814  ConvertAndAdd.......
13815 */
13816  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
13817  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
13818  ClearRoute();
13819  int TrackVectorPosition;
13820  TTrackElement TrackElement;
13821  TPrefDirElement FirstElement, LastElement;
13822 
13823  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
13824  {
13825  Utilities->CallLogPop(199);
13826  return(false);
13827  }
13828  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
13829  {
13830  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
13831  Utilities->CallLogPop(1996);
13832  return(false);
13833  }
13834  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
13835  {
13836  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
13837  Utilities->CallLogPop(200);
13838  return(false);
13839  }
13840  if(Track->IsLCAtHV(18, HLoc, VLoc))
13841  {
13842  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
13843  Utilities->CallLogPop(1909);
13844  return(false);
13845  }
13846 // check if selected a train & disallow if so
13847  if(TrackElement.TrainIDOnElement > -1)
13848  {
13849  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
13850  Utilities->CallLogPop(202);
13851  return(false);
13852  }
13853 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
13854  TPrefDirElement PrefDirElement;
13855  int LockedVectorNumber;
13856 
13857  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
13858  {
13859  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
13860  Utilities->CallLogPop(203);
13861  return(false);
13862  }
13863  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
13864  {
13865  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
13866  Utilities->CallLogPop(204);
13867  return(false);
13868  }
13870  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
13871 // signal in an autosig route & follow with a non-autosig route
13872 
13873  TPrefDirElement BlankElement;
13874 
13875  StartElement1 = BlankElement;
13876  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
13877 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
13878  bool InPrefDirFlag = false;
13879 
13880  bool FoundFlag;
13881  int PrefDirPos0 = -1;
13882  int PrefDirPos1 = -1;
13883  int PrefDirPos2 = -1;
13884  int PrefDirPos3 = -1;
13885 
13887  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13888  int PrefDirVecPos[4] =
13889  {
13890  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
13891  };
13892 
13893  for(int x = 0; x < 4; x++)
13894  {
13895  int b = PrefDirVecPos[x];
13896  if(b > -1)
13897  {
13898  // only allow the appropriate exit route to be searched
13899  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
13900  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
13901  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
13902  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
13903  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
13904  {
13905  InPrefDirFlag = true;
13906  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
13907  if(AutoSigsFlag)
13908  {
13909  StartElement1.AutoSignals = true;
13910  }
13911  StartElement1.PrefDirRoute = true;
13912  }
13913  }
13914  }
13915 
13916  if(!InPrefDirFlag)
13917  {
13919  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
13920  Utilities->CallLogPop(205);
13921  return(false);
13922  }
13923 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
13925  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
13926 
13927  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
13928  {
13929  throw Exception("Selection in two routes - should never happen!");
13930  }
13931  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
13932  {
13933  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
13934  {
13935  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
13936  Utilities->CallLogPop(206);
13937  return(false);
13938  }
13939  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
13940  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
13941  {
13942  TrainController->StopTTClockMessage(14, "No forward connection from this position");
13943  Utilities->CallLogPop(207);
13944  return(false);
13945  }
13946  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
13947  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
13948  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
13949  {
13950  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
13951  Utilities->CallLogPop(208);
13952  return(false);
13953  }
13954  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
13956  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
13957  if(AutoSigsFlag)
13958  {
13959  StartElement1.AutoSignals = true;
13960  }
13961  StartElement1.PrefDirRoute = true;
13963  Utilities->CallLogPop(209);
13964  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
13965  }
13966 
13967  else // no route started
13968  {
13969 // check if selected position is adjacent to start or end of an existing route and disallow
13970  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13971  {
13972  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
13973  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
13974  {
13975  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
13976  Utilities->CallLogPop(210);
13977  return(false);
13978  }
13979  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
13980  {
13981  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
13982  Utilities->CallLogPop(211);
13983  return(false);
13984  }
13985  }
13986 
13987 // check if it's adjacent to end of an an existing route,
13988  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
13989  {
13991  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
13992  {
13993  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
13994  Utilities->CallLogPop(212);
13995  return(false);
13996  }
13997  }
13998  SearchVector.push_back(StartElement1);
13999  Utilities->CallLogPop(213);
14000  return(true);
14001  }
14002 }
14003 
14004 // ---------------------------------------------------------------------------
14005 
14006 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14007  IDInt &ReqPosRouteID, bool &PointsChanged)
14008 
14009 /*
14010  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14011 
14012  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14013  this being set to -1 for not used.
14014  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14015  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14016  Check correct type of element - signal/buffers/continuation.
14017  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14018  EndElement2 corresponding to the 2 possible PrefDir elements).
14019  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14020  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14021  linked forward to another route.
14022  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14023  for same position as start should cover this)
14024 
14025  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14026  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14027  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14028  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14029  If the search fails then return false.
14030  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14031  in the SearchVector to ensure it's entered as part of the new route.
14032  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14033  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14034  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14035  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14036  so return false, with an appropriate message if ConsecSignalsRoute set.
14037 */
14038 
14039 {
14040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14041  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14042  int EndPosition; // the position selected
14043 
14044  Track->LCFoundInAutoSigsRoute = false;
14046  TotalSearchCount = 0;
14047  ReqPosRouteID = IDInt(-1); // default value for not used
14048  TTrackElement TrackElement;
14049  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14050  // given element as can't select 2-track elements
14051  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14052  {
14053  Utilities->CallLogPop(214);
14054  return(false);
14055  }
14056  if(Track->IsLCAtHV(19, HLoc, VLoc))
14057  {
14058  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14059  Utilities->CallLogPop(1908);
14060  return(false);
14061  }
14062 // cancel selection if on original start element
14063  if(EndPosition == StartRoutePosition)
14064  {
14065  Utilities->CallLogPop(215);
14066  return(false);
14067  }
14068  if(AutoSigsFlag)
14069  {
14070  if(TrackElement.TrackType == Buffers)
14071  {
14072  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14073  Utilities->CallLogPop(216);
14074  return(false);
14075  }
14076  }
14077  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14078  {
14079  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14080  Utilities->CallLogPop(217);
14081  return(false);
14082  }
14083 // check if train on element
14084  if(TrackElement.TrainIDOnElement > -1)
14085  {
14086  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14087  Utilities->CallLogPop(219);
14088  return(false);
14089  }
14090 // disallow if not in EveryPrefDir & set EndElement(s)
14091  bool InPrefDirFlag = false;
14092 
14093  bool FoundFlag;
14094  int PrefDirPos0 = -1;
14095  int PrefDirPos1 = -1;
14096  int PrefDirPos2 = -1;
14097  int PrefDirPos3 = -1;
14098 
14099  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14100  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14101  int PrefDirVecPos[4] =
14102  {
14103  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14104  };
14105 
14106  for(int x = 0; x < 4; x++)
14107  {
14108  int b = PrefDirVecPos[x];
14109  if(b > -1)
14110  {
14111  InPrefDirFlag = true;
14112  if(EndElement1.TrackVectorPosition == -1)
14113  {
14114  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14115  }
14116  else
14117  {
14118  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14119  }
14120  }
14121  }
14122  if(!InPrefDirFlag)
14123  {
14125  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14126  Utilities->CallLogPop(220);
14127  return(false);
14128  }
14129 // check if in an existing route - can't be a bridge so can use a simple 'find'
14130 // bool InRoute = false;
14132  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14133 
14134  if(RoutePair.first > -1)
14135  {
14136  if(RoutePair.second != 0) // not first element in existing route so no good
14137  {
14138  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14139  Utilities->CallLogPop(221);
14140  return(false);
14141  }
14142  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14143 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14144  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14145  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14146  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14147  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14148  {
14149  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14150  Utilities->CallLogPop(222);
14151  return(false);
14152  }
14153  EndElement1 = RouteElement;
14154  EndElement2 = BlankElement; // only need the route element
14155  EndPosition = EndElement1.TrackVectorPosition;
14156  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14157  }
14158 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14159 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14160 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14161 
14162  if(EndElement1.HLoc >= StartElement1.HLoc)
14163  {
14165  SearchLimitHighH = EndElement1.HLoc + 15;
14166  }
14167  else
14168  {
14169  SearchLimitLowH = EndElement1.HLoc - 15;
14171  }
14172  if(EndElement1.VLoc >= StartElement1.VLoc)
14173  {
14175  SearchLimitHighV = EndElement1.VLoc + 15;
14176  }
14177  else
14178  {
14179  SearchLimitLowV = EndElement1.VLoc - 15;
14181  }
14182 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14183  check & TotalSearchCounts check
14184  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14185  {
14186  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14187  Utilities->CallLogPop(1693);
14188  return false;
14189  }
14190 */
14191 // check if adjacent to start and disallow
14192  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14193  {
14195  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14196 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14197 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14198  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14199  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14200  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14201  {
14202  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14203  Utilities->CallLogPop(223);
14204  return(false);
14205  }
14206 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14207 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14208  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14209  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14210  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14211  {
14212  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14213  Utilities->CallLogPop(224);
14214  return(false);
14215  }
14216 // check if adjacent to end of a route & disallow
14218  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14219  {
14220  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14221  Utilities->CallLogPop(225);
14222  return(false);
14223  }
14224  }
14225 
14226 // check for same route as start element
14228  {
14229  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14230  Utilities->CallLogPop(226);
14231  return(false);
14232  }
14233 // check for a looping route
14234  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14235  {
14237  {
14238  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14239  Utilities->CallLogPop(1844);
14240  return(false);
14241  }
14242  }
14243 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14244 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14245 // and don't want to add it again
14246  if(StartSelectionRouteID > -1)
14247  {
14248  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14249  AutoSigsFlag))
14250  {
14251  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14252  if(PointsToBeChanged(5))
14253  {
14254  PointsChanged = true;
14255  }
14256  Utilities->CallLogPop(227);
14257  return(true);
14258  }
14259  else if(!Track->SuppressRouteFailMessage)
14260  {
14261  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14263  Utilities->CallLogPop(228);
14264  return(false);
14265  }
14266  }
14267  else
14268  {
14269 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14270 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14271 
14272 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14273 // note that a blank element will have XLinkPos set to -1
14274  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14275  {
14276  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14277  AutoSigsFlag))
14278  {
14279  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14280  if(PointsToBeChanged(6))
14281  {
14282  PointsChanged = true;
14283  }
14284  Utilities->CallLogPop(229);
14285  return(true);
14286  }
14287  else
14288  {
14290  {
14292  }
14293  Utilities->CallLogPop(230);
14294  return(false);
14295  }
14296  }
14297  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14298  {
14299  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14300  AutoSigsFlag))
14301  {
14302  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14303  if(PointsToBeChanged(7))
14304  {
14305  PointsChanged = true;
14306  }
14307  Utilities->CallLogPop(231);
14308  return(true);
14309  }
14310  else
14311  {
14313  {
14315  }
14316  Utilities->CallLogPop(232);
14317  return(false);
14318  }
14319  }
14320  // now start off in the best direction
14321  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14322  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14323  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14324  // unless new problems are found.
14325  if(StartElement1.XLinkPos == BestPos)
14326  {
14327  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14328  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14329  AutoSigsFlag))
14330  {
14331  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14332  if(PointsToBeChanged(8))
14333  {
14334  PointsChanged = true;
14335  }
14336  Utilities->CallLogPop(233);
14337  return(true);
14338  }
14339  else if(StartElement2.TrackVectorPosition > -1)
14340  {
14341  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14342  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14343  AutoSigsFlag))
14344  {
14345  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14346  if(PointsToBeChanged(9))
14347  {
14348  PointsChanged = true;
14349  }
14350  Utilities->CallLogPop(234);
14351  return(true);
14352  }
14353  }
14354  }
14355  else if(StartElement2.TrackVectorPosition > -1)
14356  {
14357  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14358  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14359  AutoSigsFlag))
14360  {
14361  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14362  if(PointsToBeChanged(10))
14363  {
14364  ;
14365  }
14366  {
14367  PointsChanged = true;
14368  }
14369  Utilities->CallLogPop(1857);
14370  return(true);
14371  }
14372  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14373  AutoSigsFlag))
14374  {
14375  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14376  if(PointsToBeChanged(11))
14377  {
14378  ;
14379  }
14380  {
14381  PointsChanged = true;
14382  }
14383  Utilities->CallLogPop(1858);
14384  return(true);
14385  }
14386  }
14387  else if(StartElement1.XLinkPos == (1 - BestPos))
14388  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14389  {
14390  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14391  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14392  AutoSigsFlag))
14393  {
14394  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14395  if(PointsToBeChanged(12))
14396  {
14397  PointsChanged = true;
14398  }
14399  Utilities->CallLogPop(1864);
14400  return(true);
14401  }
14402  }
14403  }
14405  {
14407  }
14408  Utilities->CallLogPop(235);
14409  return(false);
14410 }
14411 
14412 // ---------------------------------------------------------------------------
14413 
14414 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14415 {
14416  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14417  if(PrefDirSize() == 0)
14418  {
14419  Utilities->CallLogPop(1704);
14420  return;
14421  }
14422  for(unsigned int x = 0; x < PrefDirSize(); x++)
14423  {
14424  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14425  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14426  {
14427  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14428  TempPrefDirElement.EXGraphicPtr);
14429  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14430  {
14431  if(x == 0)
14432  {
14433  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14434  TempPrefDirElement.EntryDirectionGraphicPtr);
14435  }
14436  if(x == (PrefDirSize() - 1))
14437  {
14438  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14439  TempPrefDirElement.EntryDirectionGraphicPtr);
14440  }
14441  }
14442  }
14443  }
14444 
14445  Utilities->CallLogPop(1705);
14446 }
14447 
14448 // ---------------------------------------------------------------------------
14449 
14450 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14451  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14452 
14453 /*
14454  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14455  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14456  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14457  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14458  Return false if any element (apart from RequiredPosition) is on an existing route.
14459  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14460 
14461  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14462  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14463  added during the function so as to leave it exactly as it was on entering, then return false).
14464  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14465  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14466  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14467  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14468  the route number that the searched-for element is the start of if any, and set to -1 if no
14469  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14470  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14471  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14472  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14473 
14474  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14475  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14476  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14477  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
14478  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
14479  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
14480  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14481  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
14482  or if train on element (unless a bridge & train on different track).
14483  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
14484  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
14485  a leading point where both trailing directions are in EveryPrefDir, if not fail.
14486  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
14487  AutoSignals member set if AutoSigsFlag set, then return true.
14488  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
14489 
14490  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
14491  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
14492  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
14493  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
14494  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
14495  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
14496  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
14497 
14498  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
14499  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
14500 */
14501 
14502 {
14503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
14504  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
14505  AnsiString((short)AutoSigsFlag));
14506  int VectorCount = 0;
14507  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
14508 
14509 // check for a fouled diagonal for first element. Added for v1.3.2
14510  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
14511  {
14512  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
14513  {
14514  for(int x = 0; x < VectorCount; x++)
14515  {
14516  SearchVector.erase(SearchVector.end() - 1);
14517  }
14518  Utilities->CallLogPop(2043);
14519  return(false);
14520  }
14521  }
14522  bool FirstPass = true;
14523 
14524  while(true)
14525  {
14526  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
14527  {
14528  Track->LCFoundInAutoSigsRoute = true;
14529  }
14530  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
14531  {
14532  for(int x = 0; x < VectorCount; x++)
14533  {
14534  SearchVector.erase(SearchVector.end() - 1);
14535  }
14536  Utilities->CallLogPop(1926);
14537  return(false);
14538  }
14539  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
14540  {
14541  for(int x = 0; x < VectorCount; x++)
14542  {
14543  SearchVector.erase(SearchVector.end() - 1);
14544  }
14545  Utilities->CallLogPop(236);
14546  return(false);
14547  }
14548  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
14549  // reached a valid signal that isn't the required position, user should always select the next
14550  // signal in a route so have to fail
14551  // won't affect recurive searches as for them the first pass element is always a point
14552  {
14553  for(int x = 0; x < VectorCount; x++)
14554  {
14555  SearchVector.erase(SearchVector.end() - 1);
14556  }
14557  Utilities->CallLogPop(237);
14558  return(false);
14559  }
14560  FirstPass = false;
14561  int NextPosition = PrefDirElement.Conn[XLinkPos];
14562  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
14563  TPrefDirElement SearchElement(NextTrackElement);
14564  SearchElement.TrackVectorPosition = NextPosition;
14565  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
14566  SearchElement.ELinkPos = NextELinkPos;
14567  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
14568  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
14569  int NextXLinkPos;
14570  if(SearchElement.ELinkPos == 0)
14571  {
14572  NextXLinkPos = 1;
14573  }
14574  if(SearchElement.ELinkPos == 1)
14575  {
14576  NextXLinkPos = 0;
14577  }
14578  if(SearchElement.ELinkPos == 2)
14579  {
14580  NextXLinkPos = 3;
14581  }
14582  if(SearchElement.ELinkPos == 3)
14583  {
14584  NextXLinkPos = 2;
14585  }
14586  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14587  {
14588  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14589 // note that may be buffers, continuation or gap
14590  SearchElement.XLinkPos = NextXLinkPos;
14591  }
14592 // can't set XLink or XLinkPos yet if the element is a leading point.
14593 
14594 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14595  for(unsigned int x = 0; x < SearchVector.size(); x++)
14596  {
14597  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14598  {
14599  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14600  // OK if a bridge & routes on different tracks
14601  {
14602  for(int x = 0; x < VectorCount; x++)
14603  {
14604  SearchVector.erase(SearchVector.end() - 1);
14605  }
14606  Utilities->CallLogPop(238);
14607  return(false);
14608  }
14609  }
14610  }
14611 
14612 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14613  TAllRoutes::TRouteElementPair SecondPair;
14615  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14616  if(RoutePair.first > -1)
14617  {
14618  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14619  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
14620  RoutePair.second).ELinkPos)))
14621  {
14622  // still OK if start of an expected route
14623  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
14624  {
14625  for(int x = 0; x < VectorCount; x++)
14626  {
14627  SearchVector.erase(SearchVector.end() - 1);
14628  }
14629  Utilities->CallLogPop(239);
14630  return(false); // only allow for start of an expected route
14631  }
14632  }
14633  }
14634  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14635  {
14636  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14637  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
14638  SecondPair.second).ELinkPos)))
14639  {
14640  // still OK if start of an expected route
14641  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
14642  {
14643  for(int x = 0; x < VectorCount; x++)
14644  {
14645  SearchVector.erase(SearchVector.end() - 1);
14646  }
14647  Utilities->CallLogPop(240);
14648  return(false); // only allow for start of an expected route
14649  }
14650  }
14651  }
14652 // check if a train on element, unless a bridge & train on different track
14653 // OK of same train as start element - no drop this
14654 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14655  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14656  {
14657  for(int x = 0; x < VectorCount; x++)
14658  {
14659  SearchVector.erase(SearchVector.end() - 1);
14660  }
14661  Utilities->CallLogPop(241);
14662  return(false);
14663  }
14664  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14665  {
14666  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14667  {
14668  for(int x = 0; x < VectorCount; x++)
14669  {
14670  SearchVector.erase(SearchVector.end() - 1);
14671  }
14672  Utilities->CallLogPop(242);
14673  return(false);
14674  }
14675  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14676  {
14677  for(int x = 0; x < VectorCount; x++)
14678  {
14679  SearchVector.erase(SearchVector.end() - 1);
14680  }
14681  Utilities->CallLogPop(243);
14682  return(false);
14683  }
14684  }
14685 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
14686  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14687  {
14688  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14689  {
14690  for(int x = 0; x < VectorCount; x++)
14691  {
14692  SearchVector.erase(SearchVector.end() - 1);
14693  }
14694  Utilities->CallLogPop(244);
14695  return(false);
14696  }
14697  }
14698 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
14699 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
14700  bool InPrefDirFlag = false;
14701  PrefDirElement1 = BlankElement;
14702  PrefDirElement2 = BlankElement;
14703 
14704  bool FoundFlag;
14705  int PrefDirPos0 = -1;
14706  int PrefDirPos1 = -1;
14707  int PrefDirPos2 = -1;
14708  int PrefDirPos3 = -1;
14710  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14711  int PrefDirVecPos[4] =
14712  {
14713  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14714  };
14715  for(int x = 0; x < 4; x++)
14716  {
14717  int b = PrefDirVecPos[x];
14718  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
14719  {
14720  InPrefDirFlag = true;
14721  if(PrefDirElement1.TrackVectorPosition == -1)
14722  {
14723  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
14724  }
14725  else
14726  {
14727  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
14728  }
14729  }
14730  }
14731  if(!InPrefDirFlag)
14732  {
14733  for(int x = 0; x < VectorCount; x++)
14734  {
14735  SearchVector.erase(SearchVector.end() - 1);
14736  }
14737  Utilities->CallLogPop(245);
14738  return(false);
14739  }
14740 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
14741 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
14742 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
14744  {
14745  for(int x = 0; x < VectorCount; x++)
14746  {
14747  SearchVector.erase(SearchVector.end() - 1);
14748  }
14749  Utilities->CallLogPop(1690);
14750  return(false);
14751  }
14752 // check if found it
14753  if(SearchElement.TrackVectorPosition == RequiredPosition)
14754  {
14755 // need to ensure a signal/buffer/continuation
14756  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
14757  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
14758  {
14759  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
14761  for(int x = 0; x < VectorCount; x++)
14762  {
14763  SearchVector.erase(SearchVector.end() - 1);
14764  }
14765  Utilities->CallLogPop(246);
14766  return(false);
14767  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
14768 
14769  if(AutoSigsFlag)
14770  {
14771  PrefDirElement1.AutoSignals = true;
14772  }
14773  PrefDirElement1.PrefDirRoute = true;
14775  {
14777  {
14778  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
14780  }
14781  for(int x = 0; x < VectorCount; x++)
14782  {
14783  SearchVector.erase(SearchVector.end() - 1);
14784  }
14785  Utilities->CallLogPop(1928);
14786  return(false);
14787  }
14788  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
14789  VectorCount++; // not really needed but include for tidyness
14790  TotalSearchCount++;
14791  Utilities->CallLogPop(247);
14792  return(true);
14793  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
14794 
14795 // check if a buffer or continuation (end of search on this leg if not found by now)
14796  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
14797  {
14798  for(int x = 0; x < VectorCount; x++)
14799  {
14800  SearchVector.erase(SearchVector.end() - 1);
14801  }
14802  Utilities->CallLogPop(248);
14803  return(false);
14804  }
14805 // check if SearchVector exceeds a size of 150
14806  if(SearchVector.size() > 150)
14807  {
14808  for(int x = 0; x < VectorCount; x++)
14809  {
14810  SearchVector.erase(SearchVector.end() - 1);
14811  }
14812  Utilities->CallLogPop(1420);
14813  return(false);
14814  }
14815 // check if reached a leading point
14816  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
14817  {
14818 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
14819  int SearchPos1 = SearchElement.Attribute + 1;
14820  int SearchPos2;
14821  if(SearchPos1 == 2)
14822  {
14823  SearchPos1++;
14824  }
14825  if(SearchPos1 == 1)
14826  {
14827  SearchPos2 = 3;
14828  }
14829  else
14830  {
14831  SearchPos2 = 1;
14832  }
14833  SearchElement.XLink = SearchElement.Link[SearchPos1];
14834  SearchElement.XLinkPos = SearchPos1;
14835  InPrefDirFlag = false;
14836  if(SearchElement.XLink == PrefDirElement1.XLink)
14837  {
14838  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
14839  InPrefDirFlag = true;
14840  }
14841  else if(SearchElement.XLink == PrefDirElement2.XLink)
14842  {
14843  SearchElement = PrefDirElement2;
14844  InPrefDirFlag = true;
14845  }
14846 // push element with XLink set to position [SearchPos1] if on a PrefDir
14847  if(InPrefDirFlag)
14848  {
14849 // check for a fouled diagonal for leading point for XLinkPos == 1)
14850  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14851  {
14852  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14853  {
14854  for(int x = 0; x < VectorCount; x++)
14855  {
14856  SearchVector.erase(SearchVector.end() - 1);
14857  }
14858  Utilities->CallLogPop(249);
14859  return(false);
14860  }
14861  }
14862  if(AutoSigsFlag)
14863  {
14864  SearchElement.AutoSignals = true;
14865  }
14866  SearchElement.PrefDirRoute = true;
14867  SearchVector.push_back(SearchElement);
14868  VectorCount++;
14869  TotalSearchCount++;
14870 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
14871  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14872  AutoSigsFlag))
14873  {
14875  {
14877  {
14878  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
14880  }
14881  for(int x = 0; x < VectorCount; x++)
14882  {
14883  SearchVector.erase(SearchVector.end() - 1);
14884  }
14885  Utilities->CallLogPop(1929);
14886  return(false);
14887  }
14888  Utilities->CallLogPop(250);
14889  return(true);
14890  }
14891  else
14892  {
14893 // remove leading point with XLinkPos [1]
14894  SearchVector.erase(SearchVector.end() - 1);
14895  VectorCount--;
14896  }
14897  }
14898 // XLink set to position [SearchPos2]
14899  SearchElement.XLink = SearchElement.Link[SearchPos2];
14900  SearchElement.XLinkPos = SearchPos2;
14901  if(SearchElement.XLink == PrefDirElement1.XLink)
14902  {
14903  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
14904  }
14905  else if(SearchElement.XLink == PrefDirElement2.XLink)
14906  {
14907  SearchElement = PrefDirElement2;
14908  }
14909  else // failed to find a valid exit from the point
14910  {
14911  for(int x = 0; x < VectorCount; x++)
14912  {
14913  SearchVector.erase(SearchVector.end() - 1);
14914  }
14915  Utilities->CallLogPop(251);
14916  return(false);
14917  }
14918 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
14919  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14920  {
14921  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
14922  {
14923  for(int x = 0; x < VectorCount; x++)
14924  {
14925  SearchVector.erase(SearchVector.end() - 1);
14926  }
14927  Utilities->CallLogPop(252);
14928  return(false);
14929  }
14930  }
14931 // push element with XLink set to position [SearchPos2]
14932  if(AutoSigsFlag)
14933  {
14934  SearchElement.AutoSignals = true;
14935  }
14936  SearchElement.PrefDirRoute = true;
14937  SearchVector.push_back(SearchElement);
14938  VectorCount++;
14939  TotalSearchCount++;
14940 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
14941  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14942  AutoSigsFlag))
14943  {
14945  {
14947  {
14948  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
14950  }
14951  for(int x = 0; x < VectorCount; x++)
14952  {
14953  SearchVector.erase(SearchVector.end() - 1);
14954  }
14955  Utilities->CallLogPop(1930);
14956  return(false);
14957  }
14958  Utilities->CallLogPop(1592);
14959  return(true);
14960  }
14961  else
14962  {
14963  for(int x = 0; x < VectorCount; x++)
14964  {
14965  SearchVector.erase(SearchVector.end() - 1);
14966  }
14967  Utilities->CallLogPop(253);
14968  return(false);
14969  }
14970  } // if leading point
14971 
14972 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
14973  SearchElement = PrefDirElement1;
14974  if(AutoSigsFlag)
14975  {
14976  SearchElement.AutoSignals = true;
14977  }
14978  SearchElement.PrefDirRoute = true;
14979  SearchVector.push_back(SearchElement);
14980  VectorCount++;
14981  TotalSearchCount++;
14982  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
14983  PrefDirElement = SearchElement;
14984  } // while(true)
14985 }
14986 
14987 // ---------------------------------------------------------------------------
14988 
14989 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
14990 {
14991 /*
14992  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
14993  and the new or extended route created from that. Hence action varies depending on whether
14994  it is a completely new route, or an extension of an existing route at the beginning or the end.
14995  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
14996  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
14997 
14998  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
14999  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15000  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15001  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15002  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15003  is decremented;
15004  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15005  from the existing route, then enter the new route into the AllRoutesVector;
15006  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15007  then enter the new route into the AllRoutesVector.
15008 
15009  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15010  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15011  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15012  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15013  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15014  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15015  for the new route and return;
15016  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15017  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15018 
15019  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15020  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15021  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15022 
15023 */
15024  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15025  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15026  if(SearchVector.size() < 1)
15027  {
15028  Utilities->CallLogPop(254);
15029  return;
15030  }
15032  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15033  {
15034  Utilities->CallLogPop(255);
15035  return;
15036  }
15037  TAllRoutes::TLockedRouteClass LockedRouteObject;
15038 
15040  unsigned int TruncatePrefDirPosition = 0;
15041 
15042  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15043 /* if have ReqPosRouteID:
15044  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15045  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15046  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15047  the existing route, then enter the new route into the AllRoutesVector
15048  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15049  then enter the new route into the AllRoutesVector
15050 */
15051  {
15054  {
15055  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15056  x++) // start at 1 as first element already in SearchVector
15057  {
15059  }
15060  // note that route numbers in map adjusted when ReqPos route cleared
15062  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15063  // set during ClearRouteDuringRouteBuildingAt
15065  {
15068  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15069  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15070  }
15071  }
15073  {
15075  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15076  }
15078  {
15079  SearchVector.pop_back();
15080  }
15081  }
15082  if(StartSelectionRouteID > -1)
15083 /* if have StartSelectionRouteID:
15084  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15085  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15086  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15087  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15088  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15089 */
15090  {
15092  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15093  {
15096  {
15097  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15098  for(unsigned int x = 0; x < SearchVector.size(); x++)
15099  {
15101  RouteNumber, GetFixedSearchElementAt(3, x));
15102  // find & store locked route truncate position in PrefDirVector for later use
15104  {
15105  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15106  {
15107  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15108  }
15109  }
15110  }
15112  {
15113  throw Exception("Error - failed to validate extended route for preferred route");
15114  }
15117  if(!AutoSigsFlag)
15118  {
15119  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15120  }
15121  // now add the reinstated locked route if required and set signals accordingly
15123  {
15124  LockedRouteObject.RouteNumber = RouteNumber;
15125  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15126  // now reset the signals for the locked route
15127  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15128  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15129  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15130  {
15131  // return all signals to red in route section to be truncated
15132  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15133  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15134  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15135  {
15136  TrackElement.Attribute = 0;
15137  Track->PlotSignal(10, TrackElement, Display);
15138  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15139  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15140  }
15141  }
15142  }
15143  AllRoutes->CheckMapAndRoutes(1); // test
15144  Utilities->CallLogPop(256);
15145  return;
15146  }
15148  {
15151  RouteElement.AutoSignals = true;
15152  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15153  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15154  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15155  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15156  }
15157  }
15158  else
15159  {
15161  }
15162 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15163 // AllRoutesVector hence nothing to do here
15164  }
15165  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15166  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15167  {
15168  throw Exception("Error - failed to validate single route for preferred route");
15169  }
15170  AllRoutes->StoreOneRoute(1, this);
15171  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15172  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15173  if(!AutoSigsFlag)
15174  {
15175  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15176  }
15177  AllRoutes->CheckMapAndRoutes(2); // test
15178  Utilities->CallLogPop(257);
15179 }
15180 
15181 // ---------------------------------------------------------------------------
15182 
15183 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15184 {
15185 /*
15186  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15187  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15188  & ensure signal/buffers/continuation.
15189  Note that can't select ConsecSignalsRoute for non-preferred routes.
15190  Check if train on element & disallow.
15191  Set default values for retained parameters:-
15192  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15193  StartSelectionRouteID = route that selection starts in if there is one;
15194 
15195  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15196  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15197  validity. This is just for safety reasons, the PrefDir values aren't used.
15198  StartElement1 & 2 are set to these PrefDirelements.
15199 
15200  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15201 
15202  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15203  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15204  blank StartElement2 (only want to use the route element), then return true.
15205  Check if adjacent to start or end of an existing route & disallow if so.
15206  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15207  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15208  SetRemainingSearchVectorValues().
15209  Finally add the required element to the SearchVector & return true.
15210 
15211 */
15212  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15213  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15214  ClearRoute();
15215  int TrackVectorPosition;
15216  TTrackElement TrackElement;
15217  TPrefDirElement FirstElement, LastElement;
15218 
15219  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15220  {
15221  Utilities->CallLogPop(258);
15222  return(false);
15223  }
15224  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15225  {
15226  if(!Callon)
15227  {
15228  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15229  }
15230 // makes later adjacent route checks too complicated
15231  Utilities->CallLogPop(259);
15232  return(false);
15233  }
15234  if(Track->IsLCAtHV(21, HLoc, VLoc))
15235  {
15236  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15237  Utilities->CallLogPop(1910);
15238  return(false);
15239  }
15240 // check if selected a train & disallow if so
15241  if(TrackElement.TrainIDOnElement > -1)
15242  {
15243  if(!Callon)
15244  {
15245  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15246  }
15247  Utilities->CallLogPop(260);
15248  return(false);
15249  }
15250 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15251  TPrefDirElement PrefDirElement;
15252  int LockedVectorNumber;
15253 
15254  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15255  {
15256  if(!Callon)
15257  {
15258  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15259  }
15260  Utilities->CallLogPop(261);
15261  return(false);
15262  }
15263  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15264  {
15265  if(!Callon)
15266  {
15267  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15268  }
15269  Utilities->CallLogPop(262);
15270  return(false);
15271  }
15273 // AdjacentStartRouteNumber = -1;
15274  StartRoutePosition = TrackVectorPosition;
15275 // StartRouteSelectPosition = TrackVectorPosition;
15276 
15277  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15278  TPrefDirElement PrefDirElement2(TrackElement);
15279 
15280  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15281  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15282  TPrefDirElement BlankElement;
15283 
15284  PrefDirElement1.ELinkPos = 0;
15285  PrefDirElement1.XLinkPos = 1;
15286  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15287  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15288  if(!(PrefDirElement1.EntryExitNumber()))
15289  {
15290  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15291  // no need for bridge check as bridge selections not allowed
15292  }
15293  PrefDirElement1.CheckCount = 9;
15294  PrefDirElement2.ELinkPos = 1;
15295  PrefDirElement2.XLinkPos = 0;
15296  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15297  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15298  if(!(PrefDirElement2.EntryExitNumber()))
15299  {
15300  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15301  }
15302  PrefDirElement2.CheckCount = 9; // both now set
15303 
15304 // set StartElements to the above PrefDirElements
15305  StartElement1 = PrefDirElement1;
15306  StartElement2 = PrefDirElement2;
15307 
15308 // no PrefDir check needed as doesn't need to be in a PrefDir
15309 
15310 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15312  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15313 
15314  if(RoutePair.first > -1)
15315  {
15316  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15317  {
15318  if(!Callon)
15319  {
15320  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15321  }
15322  Utilities->CallLogPop(263);
15323  return(false);
15324  }
15325  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15326  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15327  {
15328  if(!Callon)
15329  {
15330  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15331  }
15332  Utilities->CallLogPop(264);
15333  return(false);
15334  }
15335  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15336  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15337  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15338  {
15339  if(!Callon)
15340  {
15341  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15342  }
15343  Utilities->CallLogPop(265);
15344  return(false);
15345  }
15346  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15348  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15349  StartElement2 = BlankElement; // only use the route element
15351  Utilities->CallLogPop(266);
15352  return(true); // all retained values set
15353  }
15354 
15355  else // selection not in an existing route
15356  {
15357 // check if it's adjacent to start of an an existing route,
15358  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15359  {
15360  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15361  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15362  {
15363  if(!Callon)
15364  {
15365  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15366  }
15367  Utilities->CallLogPop(267);
15368  return(false);
15369  }
15370  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15371  {
15372  if(!Callon)
15373  {
15374  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15375  }
15376  Utilities->CallLogPop(268);
15377  return(false);
15378  }
15379  }
15380 // check if it's adjacent to end of an an existing route,
15381  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15382  {
15384  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15385  {
15386  if(!Callon)
15387  {
15388  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15389  }
15390  Utilities->CallLogPop(269);
15391  return(false);
15392  }
15393  }
15394  // not in a route or adjacent to start or end of a route
15395  // in this case reset all variable values to -1 & CheckCount to 4
15396  StartElement1.ELink = -1;
15397  StartElement1.ELinkPos = -1;
15398  StartElement1.XLink = -1;
15399  StartElement1.XLinkPos = -1;
15400  StartElement1.EXNumber = -1;
15402  StartElement2 = BlankElement;
15403  SearchVector.push_back(StartElement1);
15404  Utilities->CallLogPop(270);
15405  return(true);
15406  }
15407 }
15408 
15409 // ---------------------------------------------------------------------------
15410 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15411 
15412 /*
15413  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15414 
15415  Declare the following integers:-
15416  EndPosition - TrackVectorPosition for the selection;
15417  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15418  Check if selection is a valid track element and set EndPosition.
15419  Cancel if select original start element, then check that not points, bridge or crossover.
15420  Check & fail if a train is present at the selection.
15421  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15422  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15423  No check needed for selection in EveryPrefDir.
15424  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15425  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15426  as don't need it if in a route.
15427  Check if selection adj to start or end of a route and disallow.
15428  Fail if select same route as starting route, though should already have failed earlier if this is so.
15429 
15430  If there's a StartSelectionRouteID then StartElement1 will be set to
15431  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15432  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15433  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15434  to add the new route to the AllRoutesVectorPtr.
15435  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15436  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15437  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15438  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15439  the search vector values and return.
15440  If not returned yet then have failed to find the required element so return false with no message.
15441 
15442 */
15443 
15444 {
15445 // get EndPosition
15446  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15447  AnsiString(VLoc));
15448  int EndPosition;
15449 
15450  TotalSearchCount = 0;
15451  ReqPosRouteID = IDInt(-1); // for not used
15452  TTrackElement TrackElement;
15453  TPrefDirElement BlankElement;
15454 
15455  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15456  {
15457  Utilities->CallLogPop(271);
15458  return(false);
15459  }
15460 // EndPosition = EndSelectPosition;
15461 // cancel selection if on original start element
15462  if(EndPosition == StartRoutePosition)
15463  {
15464  Utilities->CallLogPop(272);
15465  return(false);
15466  }
15467  if(Track->IsLCAtHV(22, HLoc, VLoc))
15468  {
15469  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15470  Utilities->CallLogPop(1911);
15471  return(false);
15472  }
15473  if((TrackElement.TrackType == Points) && !Callon)
15474  {
15475  if(!Callon)
15476  {
15477  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
15478  }
15479 // makes later adjacent route checks too complicated
15480  Utilities->CallLogPop(273);
15481  return(false);
15482  }
15483  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15484  {
15485  if(!Callon)
15486  {
15487  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
15488  }
15489 // makes later adjacent route checks too complicated
15490  Utilities->CallLogPop(1861);
15491  return(false);
15492  }
15493 // check if train on element
15494  if(TrackElement.TrainIDOnElement > -1)
15495  {
15496  if(!Callon)
15497  {
15498  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
15499  }
15500  Utilities->CallLogPop(274);
15501  return(false);
15502  }
15503 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
15504 // check passed)
15505  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15506  TPrefDirElement EndElement2(TrackElement);
15507 
15508  EndElement1.TrackVectorPosition = EndPosition;
15509  EndElement2.TrackVectorPosition = EndPosition;
15510  EndElement1.ELinkPos = 0;
15511  EndElement1.XLinkPos = 1;
15512  EndElement1.ELink = EndElement1.Link[0];
15513  EndElement1.XLink = EndElement1.Link[1];
15514  if(!(EndElement1.EntryExitNumber()))
15515  {
15516  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
15517  }
15518  EndElement1.CheckCount = 9;
15519  EndElement2.ELinkPos = 1;
15520  EndElement2.XLinkPos = 0;
15521  EndElement2.ELink = EndElement2.Link[1];
15522  EndElement2.XLink = EndElement2.Link[0];
15523  if(!(EndElement2.EntryExitNumber()))
15524  {
15525  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
15526  }
15527  EndElement2.CheckCount = 9; // both now set
15528 
15529 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15530 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15531 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15532 
15533  if(EndElement1.HLoc >= StartElement1.HLoc)
15534  {
15536  SearchLimitHighH = EndElement1.HLoc + 15;
15537  }
15538  else
15539  {
15540  SearchLimitLowH = EndElement1.HLoc - 15;
15542  }
15543  if(EndElement1.VLoc >= StartElement1.VLoc)
15544  {
15546  SearchLimitHighV = EndElement1.VLoc + 15;
15547  }
15548  else
15549  {
15550  SearchLimitLowV = EndElement1.VLoc - 15;
15552  }
15553 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15554  check & TotalSearchCounts check
15555  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15556  {
15557  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
15558  Utilities->CallLogPop(1694);
15559  return false;
15560  }
15561 */
15562 // don't need EveryPrefDir check for NonPreferredRoute
15563 
15564 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
15565 // bool InRoute = false;
15567  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15568 
15569  if(RoutePair.first > -1)
15570  {
15571  if(RoutePair.second != 0) // not first element in existing route so no good
15572  {
15573  if(!Callon)
15574  {
15575  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
15576  }
15577  Utilities->CallLogPop(275);
15578  return(false);
15579  }
15580  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
15581 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15582  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
15583  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15584  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15585  {
15586  if(!Callon)
15587  {
15588  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
15589  }
15590  Utilities->CallLogPop(276);
15591  return(false);
15592  }
15593  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
15594  EndElement2 = BlankElement; // only need the route element
15595  EndPosition = EndElement1.TrackVectorPosition;
15596  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
15597  }
15598 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
15599  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15600  {
15601  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
15602  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
15603 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15604 // && (AdjPosition != StartRoutePosition))
15605  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15606  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15607  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
15608  {
15609  if(!Callon)
15610  {
15611  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
15612  }
15613  Utilities->CallLogPop(277);
15614  return(false);
15615  }
15616 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15617 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
15618  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15619  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15620  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
15621  (AdjPosition != StartRoutePosition))
15622  {
15623  if(!Callon)
15624  {
15625  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
15626  }
15627  Utilities->CallLogPop(278);
15628  return(false);
15629  }
15630 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
15632  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
15633  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
15634  {
15635  if(!Callon)
15636  {
15637  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
15638  }
15639  Utilities->CallLogPop(279);
15640  return(false);
15641  }
15642  }
15643 
15644 // check for same route as start element
15646  {
15647  if(!Callon)
15648  {
15649  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
15650  }
15651  Utilities->CallLogPop(280);
15652  return(false);
15653  }
15654 // check for a looping route
15655  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15656  {
15658  {
15659  if(!Callon)
15660  {
15661  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
15662  }
15663  Utilities->CallLogPop(1845);
15664  return(false);
15665  }
15666  }
15667 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15668 // so search from this element.
15669 
15670  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
15671 
15672  if(StartSelectionRouteID > -1)
15673  {
15674  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
15675  {
15677  if(PointsToBeChanged(0))
15678  {
15679  PointsChanged = true;
15680  }
15681  Utilities->CallLogPop(281);
15682  return(true);
15683  }
15684  else
15685  {
15686  if(!Callon)
15687  {
15689  }
15690  Utilities->CallLogPop(282);
15691  return(false);
15692  }
15693  }
15694  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
15695  // search on the 2 ways out of the element, which has to be a 2-ended element
15696  {
15697 // check if selection adjacent to start element and if so use that
15698  if(SearchVector.at(0).Conn[0] == EndPosition)
15699  {
15700  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
15701  {
15703  if(PointsToBeChanged(1))
15704  {
15705  PointsChanged = true;
15706  }
15707  Utilities->CallLogPop(283);
15708  return(true);
15709  }
15710  else
15711  {
15712  if(!Callon)
15713  {
15715  }
15716  Utilities->CallLogPop(284);
15717  return(false);
15718  }
15719  }
15720  else if(SearchVector.at(0).Conn[1] == EndPosition)
15721  {
15722  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
15723  {
15725  if(PointsToBeChanged(2))
15726  {
15727  PointsChanged = true;
15728  }
15729  Utilities->CallLogPop(285);
15730  return(true);
15731  }
15732  else
15733  {
15734  if(!Callon)
15735  {
15737  }
15738  Utilities->CallLogPop(286);
15739  return(false);
15740  }
15741  }
15742  // now start off in the best direction
15743  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
15744 
15745  if(SearchVector.at(0).Config[BestPos] != End)
15746  {
15747  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15748  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
15749  {
15751  if(PointsToBeChanged(3))
15752  {
15753  PointsChanged = true;
15754  }
15755  Utilities->CallLogPop(287);
15756  return(true);
15757  }
15758  }
15759  if(SearchVector.at(0).Config[1 - BestPos] != End)
15760  {
15761  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
15762  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
15763  {
15765  if(PointsToBeChanged(4))
15766  {
15767  PointsChanged = true;
15768  }
15769  Utilities->CallLogPop(288);
15770  return(true);
15771  }
15772  }
15773  }
15774  if(!Callon)
15775  {
15777  }
15778  Utilities->CallLogPop(289);
15779  return(false);
15780 }
15781 
15782 // ---------------------------------------------------------------------------
15783 
15784 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
15785 /*
15786  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
15787  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
15788  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
15789  Keep a count of entries in SearchVector during the current function call, so that this number can be
15790  erased for an unproductive branch search.
15791  First check (within the loop) whether XLink leads to an End & return false if so.
15792  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
15793  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
15794  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
15795  train on element (unless a bridge & train on different track), or if element
15796  fouls an existing diagonal route (except if element is a leading point - these checked later).
15797  Then check if found required element. If so save it & return true.
15798  If not the required element check if buffer or continuation, & if so erase all searchvector
15799  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
15800  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
15801  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
15802  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
15803  When return true have 8 items from CheckCount established, only waiting for EXNumber
15804 */
15805 {
15806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
15807  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
15808  int VectorCount = 0;
15809 
15810 // check for a fouled diagonal for first element. Added for v1.3.2
15811  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
15812  (CurrentTrackElement.Link[XLinkPos] == 9))
15813  {
15814  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
15815  {
15816  for(int x = 0; x < VectorCount; x++)
15817  {
15818  SearchVector.erase(SearchVector.end() - 1);
15819  }
15820  Utilities->CallLogPop(2044);
15821  return(false);
15822  }
15823  }
15824  while(true)
15825  {
15826  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
15827  {
15828  for(int x = 0; x < VectorCount; x++)
15829  {
15830  SearchVector.erase(SearchVector.end() - 1);
15831  }
15832  Utilities->CallLogPop(1927);
15833  return(false);
15834  }
15835  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
15836  {
15837  for(int x = 0; x < VectorCount; x++)
15838  {
15839  SearchVector.erase(SearchVector.end() - 1);
15840  }
15841  Utilities->CallLogPop(290);
15842  return(false);
15843  }
15844  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
15845  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
15846  TPrefDirElement SearchElement(NextTrackElement);
15847  SearchElement.TrackVectorPosition = NextPosition;
15848  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
15849  SearchElement.ELinkPos = NextELinkPos;
15850  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
15851  int NextXLinkPos;
15852  if(SearchElement.ELinkPos == 0)
15853  {
15854  NextXLinkPos = 1;
15855  }
15856  if(SearchElement.ELinkPos == 1)
15857  {
15858  NextXLinkPos = 0;
15859  }
15860  if(SearchElement.ELinkPos == 2)
15861  {
15862  NextXLinkPos = 3;
15863  }
15864  if(SearchElement.ELinkPos == 3)
15865  {
15866  NextXLinkPos = 2;
15867  }
15868  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
15869  {
15870  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
15871  // but may be buffers, continuation or gap
15872  SearchElement.XLinkPos = NextXLinkPos;
15873  }
15874 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
15875 // can't set XLink or XLinkPos yet if the element is a leading point.
15876 
15877 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
15878  for(unsigned int x = 0; x < SearchVector.size(); x++)
15879  {
15880  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
15881  {
15882  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
15883  // OK if it's a bridge & routes on different tracks
15884  {
15885  for(int x = 0; x < VectorCount; x++)
15886  {
15887  SearchVector.erase(SearchVector.end() - 1);
15888  }
15889  Utilities->CallLogPop(291);
15890  return(false);
15891  }
15892  }
15893  }
15894 
15895 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
15896  TAllRoutes::TRouteElementPair SecondPair;
15898  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
15899  if(RoutePair.first > -1)
15900  {
15901  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
15902  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
15903  RoutePair.second).ELinkPos)))
15904  {
15905  // still OK if start of an expected route
15906  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
15907  {
15908  for(int x = 0; x < VectorCount; x++)
15909  {
15910  SearchVector.erase(SearchVector.end() - 1);
15911  }
15912  Utilities->CallLogPop(292);
15913  return(false); // only allow for start of an expected route
15914  }
15915  }
15916  }
15917  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
15918  {
15919  // OK if it's a bridge & routes on different tracks
15920  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
15921  SecondPair.second).ELinkPos)))
15922  {
15923  // still OK if start of an expected route
15924  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
15925  {
15926  for(int x = 0; x < VectorCount; x++)
15927  {
15928  SearchVector.erase(SearchVector.end() - 1);
15929  }
15930  Utilities->CallLogPop(293);
15931  return(false); // only allow for start of an expected route
15932  }
15933  }
15934  }
15935 // check if a train on element, unless a bridge & train on different track
15936 // OK of same train as start element - no, drop this
15937 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
15938  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
15939  {
15940  for(int x = 0; x < VectorCount; x++)
15941  {
15942  SearchVector.erase(SearchVector.end() - 1);
15943  }
15944  Utilities->CallLogPop(294);
15945  return(false);
15946  }
15947  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
15948  {
15949  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
15950  {
15951  for(int x = 0; x < VectorCount; x++)
15952  {
15953  SearchVector.erase(SearchVector.end() - 1);
15954  }
15955  Utilities->CallLogPop(295);
15956  return(false);
15957  }
15958  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
15959  {
15960  for(int x = 0; x < VectorCount; x++)
15961  {
15962  SearchVector.erase(SearchVector.end() - 1);
15963  }
15964  Utilities->CallLogPop(296);
15965  return(false);
15966  }
15967  }
15968 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
15969  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15970  {
15971  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15972  {
15973  for(int x = 0; x < VectorCount; x++)
15974  {
15975  SearchVector.erase(SearchVector.end() - 1);
15976  }
15977  Utilities->CallLogPop(297);
15978  return(false);
15979  }
15980  }
15981 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15982 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15983 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15985  {
15986  for(int x = 0; x < VectorCount; x++)
15987  {
15988  SearchVector.erase(SearchVector.end() - 1);
15989  }
15990  Utilities->CallLogPop(1689);
15991  return(false);
15992  }
15993 // check if found it
15994  if(SearchElement.TrackVectorPosition == RequiredPosition)
15995  {
15996  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
15997  {
15998  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
15999  {
16000  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16001  }
16002  else
16003  {
16004  SearchElement.XLinkPos = 1;
16005  }
16006 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16007  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16008  }
16009  SearchVector.push_back(SearchElement);
16010  VectorCount++; // not really needed but include for tidyness
16011  TotalSearchCount++;
16012  Utilities->CallLogPop(298);
16013  return(true);
16014  }
16015 // Not the required element - check if a buffer or continuation
16016  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16017  {
16018  for(int x = 0; x < VectorCount; x++)
16019  {
16020  SearchVector.erase(SearchVector.end() - 1);
16021  }
16022  Utilities->CallLogPop(299);
16023  return(false);
16024  }
16025 // check if SearchVector exceeds a size of 150
16026  if(SearchVector.size() > 150)
16027  {
16028  for(int x = 0; x < VectorCount; x++)
16029  {
16030  SearchVector.erase(SearchVector.end() - 1);
16031  }
16032  Utilities->CallLogPop(1421);
16033  return(false);
16034  }
16035 // check if reached a leading point
16036  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16037  {
16038 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16039  int SearchPos1 = SearchElement.Attribute + 1;
16040  int SearchPos2;
16041  if(SearchPos1 == 2)
16042  {
16043  SearchPos1++;
16044  }
16045  if(SearchPos1 == 1)
16046  {
16047  SearchPos2 = 3;
16048  }
16049  else
16050  {
16051  SearchPos2 = 1;
16052  }
16053 // push element with XLink set to position [SearchPos1]
16054  SearchElement.XLink = SearchElement.Link[SearchPos1];
16055  SearchElement.XLinkPos = SearchPos1;
16056 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16057  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16058  {
16059  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16060  {
16061  for(int x = 0; x < VectorCount; x++)
16062  {
16063  SearchVector.erase(SearchVector.end() - 1);
16064  }
16065  Utilities->CallLogPop(300);
16066  return(false);
16067  }
16068  }
16069  SearchVector.push_back(SearchElement);
16070  VectorCount++;
16071  TotalSearchCount++;
16072 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16073 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16074 // recursive search as has to be a TTrackElement for non-preferred route searches
16075  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16076  {
16077  Utilities->CallLogPop(301);
16078  return(true);
16079  }
16080  else
16081  {
16082 // remove leading point with XLinkPos [SearchPos1]
16083  SearchVector.erase(SearchVector.end() - 1);
16084  VectorCount--;
16085 // push element with XLink set to position [SearchPos2]
16086  SearchElement.XLink = SearchElement.Link[SearchPos2];
16087  SearchElement.XLinkPos = SearchPos2;
16088 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16089  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16090  {
16091  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16092  {
16093  for(int x = 0; x < VectorCount; x++)
16094  {
16095  SearchVector.erase(SearchVector.end() - 1);
16096  }
16097  Utilities->CallLogPop(302);
16098  return(false);
16099  }
16100  }
16101  SearchVector.push_back(SearchElement);
16102  VectorCount++;
16103  TotalSearchCount++;
16104 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16105  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16106  {
16107  Utilities->CallLogPop(303);
16108  return(true);
16109  }
16110  else
16111  {
16112  for(int x = 0; x < VectorCount; x++)
16113  {
16114  SearchVector.erase(SearchVector.end() - 1);
16115  }
16116  Utilities->CallLogPop(304);
16117  return(false);
16118  }
16119  }
16120  } // if leading point
16121 
16122 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16123 // ready for next element on route
16124  SearchVector.push_back(SearchElement);
16125  VectorCount++;
16126  TotalSearchCount++;
16127  CurrentTrackElement = SearchElement;
16128  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16129  } // while(true)
16130 }
16131 
16132 // ---------------------------------------------------------------------------
16133 
16135 
16136 /*
16137  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16138  having all values set (since not necessarily on PrefDirs).
16139  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16140  (if it was the start), so these are checked first and set if necessary. All elements now have
16141  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16142  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16143  to set the route colour and direction graphics.
16144 */
16145 
16146 {
16147  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16148  if(SearchVector.size() == 0)
16149  {
16150  throw Exception("Error, SearchVector empty");
16151  }
16152 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16153 // hence need to examine and update it if necessary
16154  TPrefDirElement SecondElement;
16155 
16156  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16157  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16158  // need above check or SecondElement will fail
16159  {
16160  SecondElement = SearchVector.at(1);
16161  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16162  for(int x = 0; x < 4; x++)
16163  {
16164  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16165  {
16166  if(SearchVector.at(0).XLink == -1) // i.e. not set
16167  {
16168  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16169  SearchVector.at(0).XLinkPos = x;
16170  }
16171  int ELinkPos;
16172  if(SearchVector.at(0).XLinkPos == 0)
16173  {
16174  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16175  }
16176  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16177  if(SearchVector.at(0).XLinkPos == 1)
16178  {
16179  ELinkPos = 0;
16180  }
16181  if(SearchVector.at(0).XLinkPos == 2)
16182  {
16183  ELinkPos = 3;
16184  }
16185  if(SearchVector.at(0).XLinkPos == 3)
16186  {
16187  ELinkPos = 2;
16188  }
16189  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16190  {
16191  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16192  SearchVector.at(0).ELinkPos = ELinkPos;
16193  }
16194  break; // no point going any further
16195  }
16196  }
16197  }
16198  for(unsigned int x = 0; x < SearchVector.size(); x++)
16199  {
16200  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16201 // set EXNumber
16202  if(!(SearchVector.at(x).EntryExitNumber()))
16203  {
16204  throw Exception("Error in EntryExitNumber 3");
16205  }
16206  SearchVector.at(x).CheckCount++;
16207 // all values now incorporated
16208  }
16209 
16210  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16211 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16212 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16213  Utilities->CallLogPop(305);
16214 }
16215 
16216 // ---------------------------------------------------------------------------
16217 
16219 
16220 /*
16221  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16222  AutoSigsRoute.
16223  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16224  beginning or the end.
16225  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16226  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16227  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16228  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16229  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16230  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16231  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16232 
16233  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16234  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16235  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16236  route at the start.
16237 
16238  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16239  for the new route and return.
16240 */
16241 
16242 {
16243  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16244  AnsiString(ReqPosRouteID.GetInt()));
16245  if(SearchVector.size() < 1)
16246  {
16247  Utilities->CallLogPop(306);
16248  return;
16249  }
16250  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16251  if(!ValidatePrefDir(6))
16252  {
16253  Utilities->CallLogPop(307);
16254  return;
16255  }
16256  TAllRoutes::TLockedRouteClass LockedRouteObject;
16257 
16259  unsigned int TruncatePrefDirPosition = 0;
16260 
16261  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16262 /* if have ReqPosRouteID:
16263  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16264  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16265  then enter the new route into the AllRoutesVector
16266 */
16267  {
16269  {
16270  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16271  x++) // start at 1 as first element already in SearchVector
16272  {
16274  }
16275  // note that route numbers in map adjusted when ReqPos route cleared
16277  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16278  // set during ClearRouteDuringRouteBuildingAt)
16280  {
16283  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16284  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16285  }
16286  }
16288  {
16289  SearchVector.pop_back();
16290  }
16291  }
16292  if(StartSelectionRouteID > -1)
16293 /* if have StartSelectionRouteID:
16294  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16295  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16296 */
16297  {
16299  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16300  {
16302  {
16303  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16304  for(unsigned int x = 0; x < SearchVector.size(); x++)
16305  {
16307  RouteNumber, GetFixedSearchElementAt(7, x));
16308  // find & store locked route truncate position in PrefDirVector for later use
16310  {
16311  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16312  {
16313  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16314  }
16315  }
16316  }
16318  {
16319  throw Exception("Failed to validate extended route for nonpreferred route");
16320  }
16323  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16324  // now add the reinstated locked route if required and set signals accordingly
16325  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16326  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16327  // that I haven't thought of
16329  {
16330  LockedRouteObject.RouteNumber = RouteNumber;
16331  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16332  // now reset the signals for the locked route
16333  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16334  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16335  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16336  {
16337  // return all signals to red in route section to be truncated
16338  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16339  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16340  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16341  {
16342  TrackElement.Attribute = 0;
16343  Track->PlotSignal(11, TrackElement, Display);
16344  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16345  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16346  }
16347  }
16348  }
16349  AllRoutes->CheckMapAndRoutes(3); // test
16350  Utilities->CallLogPop(308);
16351  return;
16352  }
16353  }
16354  else
16355  {
16357  }
16358 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16359 // hence nothing to do here
16360  }
16361  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16362  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16363  {
16364  throw Exception("Failed to validate single route for nonpreferred route");
16365  }
16366  AllRoutes->StoreOneRoute(2, this);
16367  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16368  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16369  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16370  AllRoutes->CheckMapAndRoutes(4); // test
16371  Utilities->CallLogPop(309);
16372 }
16373 
16374 // ---------------------------------------------------------------------------
16375 
16376 void TOneRoute::SetRoutePoints(int Caller) const
16377 /*
16378  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16379  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16380  when they were created.
16381 */
16382 {
16383  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16384  if(!PrefDirVector.empty())
16385  {
16386  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16387  {
16388  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16389  {
16390  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16391  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16392  }
16393  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16394  {
16395  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16396  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16397  }
16398  }
16399  }
16400  Utilities->CallLogPop(327);
16401 }
16402 
16403 // ---------------------------------------------------------------------------
16404 
16405 void TOneRoute::SetRouteSignals(int Caller) const
16406 /* Used for new train additions in AddTrain and in route setting
16407  Set the signals as follows:-
16408  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16409  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16410  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16411  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16412  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16413  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16414  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16415  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16416  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16417 
16418  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16419  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16420  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16421  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16422  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16423  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16424  as a green signal.
16425 */
16426 {
16427  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16428  if(!PrefDirVector.empty())
16429  {
16430  // get target Attribute value, check first if there is a forward linked route
16431  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16432  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16433  int ForwardLinkedRouteNumber, Attribute = 0;
16434  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16435  // Note that LastElement can't be points but can be linked to points
16436  {
16437  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16438  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16439  {
16440  if(ForwardLinkedRouteNumber > -1)
16441  {
16442  int NextForwardLinkedRouteNumber = -1;
16443  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16444  Attribute)))
16445  {
16446  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16447  }
16448  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16449  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16450  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16451  }
16452  }
16453  }
16454  int RouteNumber;
16455  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16456  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16457  if(RouteType != TAllRoutes::NoRoute)
16458  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16459  {
16460  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16461  }
16462  }
16463  Utilities->CallLogPop(1720);
16464 }
16465 
16466 // ---------------------------------------------------------------------------
16467 
16468 bool TOneRoute::PointsToBeChanged(int Caller) const
16469 {
16470  // true if at any point in SearchVector points have to be changed
16471  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16472  if(!SearchVector.empty())
16473  {
16474  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16475  {
16476  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16477  {
16478  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
16479  {
16480  Utilities->CallLogPop(1717);
16481  return(true);
16482  }
16483  }
16484  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
16485  {
16486  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
16487  {
16488  Utilities->CallLogPop(1718);
16489  return(true);
16490  }
16491  }
16492  }
16493  }
16494  Utilities->CallLogPop(1719);
16495  return(false);
16496 }
16497 
16498 // ---------------------------------------------------------------------------
16499 
16500 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
16501 /*
16502  Works forward through the route until finds:-
16503  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16504  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
16505  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
16506  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16507  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
16508  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
16509  returns true;
16510  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
16511 */
16512 {
16513  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
16514  Attribute = 0;
16515  NextForwardLinkedRouteNumber = -1;
16516  for(unsigned int x = 0; x < PrefDirSize(); x++)
16517  {
16518  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
16519  if(PrefDirVector.at(x).TrackType == Bridge)
16520  {
16521  if(PrefDirVector.at(x).XLinkPos < 2)
16522  {
16523  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16524  }
16525  else
16526  {
16527  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16528  }
16529  }
16530  if(TrainID != -1)
16531  {
16532  Utilities->CallLogPop(328);
16533  return(true);
16534  }
16535  if(PrefDirVector.at(x).TrackType == Buffers)
16536  {
16537  Attribute = 1;
16538  Utilities->CallLogPop(329);
16539  return(true);
16540  }
16541  if(PrefDirVector.at(x).TrackType == Continuation)
16542  {
16543  Attribute = 3;
16544  Utilities->CallLogPop(330);
16545  return(true);
16546  }
16547  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16548  {
16549  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16550  {
16551  Attribute = 0;
16552  Utilities->CallLogPop(1950);
16553  return(true);
16554  }
16555  }
16556  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
16557  {
16558  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
16559  if(Attribute > 3)
16560  {
16561  Attribute = 3;
16562  }
16563  Utilities->CallLogPop(331);
16564  return(true);
16565  }
16566  if(x == PrefDirSize() - 1)
16567  {
16568  TPrefDirElement LastElement = PrefDirVector.at(x);
16569  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16570  {
16571  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
16572  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16573  {
16574  Attribute = 0;
16575  Utilities->CallLogPop(332);
16576  return(false);
16577  }
16578  }
16579  }
16580  }
16581  Utilities->CallLogPop(333);
16582  return(true);
16583 }
16584 
16585 // ---------------------------------------------------------------------------
16586 
16587 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
16588 /*
16589  This function is only called by TAllRoutes::SetAllRearwardsSignals.
16590 
16591  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16592  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16593  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16594  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16595  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16596  a route.
16597 
16598  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16599  signal. If find a signal (but see note below) set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16600  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3. On completion Attribute is
16601  passed back from the function as a reference. If no train is found before the beginning of the route is reached the function returns true.
16602 
16603  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
16604  and the next rearwards signal becomes yellow, although it's the first in the route
16605 */
16606 {
16607  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
16608  AnsiString(PrefDirVectorStartPosition));
16609  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
16610  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
16611 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
16612 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
16613  bool SkipContinuationAndBufferAttributeChange = false;
16614 
16615  if(!PrefDirVector.empty())
16616  {
16617  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
16618  {
16619  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16620  if(PrefDirPtr->TrackType == Bridge)
16621  {
16622  if(PrefDirPtr->XLinkPos < 2)
16623  {
16624  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16625  }
16626  else
16627  {
16628  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16629  }
16630  }
16631  if(TrainID != -1)
16632  {
16633  SkipContinuationAndBufferAttributeChange = true;
16634  break;
16635  }
16636  }
16637 
16640  {
16641  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
16642  AutoSigVectorIT++)
16643  {
16644  if(!AllRoutes->AllRoutesVector.empty())
16645  {
16646  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
16647  {
16648  SkipContinuationAndBufferAttributeChange = true;
16649  break;
16650  }
16651  }
16652  }
16653  }
16655  {
16656  SkipContinuationAndBufferAttributeChange = true;
16657  }
16658  if(!SkipContinuationAndBufferAttributeChange)
16659  {
16660  if(PrefDirVector.back().TrackType == Buffers)
16661  {
16662  Attribute = 1; // treat buffer as red signal
16663  }
16664  if(PrefDirVector.back().TrackType == Continuation)
16665  {
16666  Attribute = 3; // treat continuation as a green signal
16667  }
16668  }
16669  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16670  {
16671  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16672  if(PrefDirPtr->TrackType == Bridge)
16673  {
16674  if(PrefDirPtr->XLinkPos < 2)
16675  {
16676  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16677  }
16678  else
16679  {
16680  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16681  }
16682  }
16683  if(TrainID != -1)
16684  {
16685  Utilities->CallLogPop(334);
16686  return(false);
16687  }
16688  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
16689  // the attribute to 0 so first signal behind the LC is red
16690  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
16691  {
16692  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
16693  {
16694  Attribute = 0;
16695  }
16696  }
16697 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
16698 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
16699  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
16700  {
16701  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
16702  PrefDirPtr->PrefDirRoute)
16703  {
16704  if(Attribute < 3)
16705  {
16706  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
16707  }
16708  else
16709  {
16710  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
16711  }
16712  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
16713  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
16714  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
16715  {
16716  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
16717  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
16718  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
16719  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
16720  }
16721  if(Attribute < 3)
16722  {
16723  Attribute++;
16724  }
16725  Display->Update(); // update after recent plots
16726  }
16727  }
16728  }
16729  }
16730  Utilities->CallLogPop(335);
16731  return(true);
16732 }
16733 
16734 // ---------------------------------------------------------------------------
16735 
16736 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
16737 /*
16738  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
16739  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
16740  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
16741  Selection invalid if select a bridge; trying to leave a single element; last element to be left
16742  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
16743  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
16744  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
16745  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
16746 */
16747 {
16748  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
16749  "," + AnsiString((short)PrefDirRoute));
16750  bool ElementInRoute = false;
16751  bool TrainOccupyingRoute = false;
16752 
16753  for(unsigned int b = 0; b < PrefDirSize(); b++)
16754  {
16755  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
16756  {
16757  ElementInRoute = true;
16758  break;
16759  }
16760  }
16761  if(!ElementInRoute)
16762  {
16763  ReturnFlag = NotInRoute;
16764  Utilities->CallLogPop(336);
16765  return;
16766  }
16767 // it is in the route so continue, first look for a train or a flashing level crossing
16768  for(int b = PrefDirSize() - 1; b >= 0; b--)
16769  {
16770  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
16771  if(PrefDirVector.at(b).TrackType == Bridge)
16772  {
16773  if(PrefDirVector.at(b).XLinkPos < 2)
16774  {
16775  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16776  }
16777  else
16778  {
16779  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16780  }
16781  }
16782  if(TrainID != -1)
16783  {
16784 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
16785 // ReturnFlag = InRouteFalse;
16786 // Utilities->CallLogPop(337);
16787 // return;
16788 // above removed at v2.1.0 so that routes can be locked when occupied, below added
16789  TrainOccupyingRoute = true; // train is forward of the truncate point
16790  }
16791  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
16792  {
16793  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
16794  ReturnFlag = InRouteFalse;
16795  Utilities->CallLogPop(1941);
16796  return;
16797  }
16798  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
16799  {
16800  break; // OK found truncate element & no flashing LC in front
16801  }
16802  }
16803 
16804  for(unsigned int b = 0; b < PrefDirSize(); b++)
16805  {
16806  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
16807  {
16808  if(PrefDirVector.at(b).TrackType == Bridge)
16809  {
16810  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
16811  ReturnFlag = InRouteFalse;
16812  Utilities->CallLogPop(338);
16813  return;
16814  }
16815  if(b == 1)
16816  {
16817  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
16818  ReturnFlag = InRouteFalse;
16819  Utilities->CallLogPop(339);
16820  return;
16821  }
16822  if(b > 0)
16823  {
16824  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
16825  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
16826  {
16827  if(TempElement.Config[TempElement.XLinkPos] != Signal)
16828  {
16829  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
16830  ReturnFlag = InRouteFalse;
16831  Utilities->CallLogPop(340);
16832  return;
16833  }
16834  }
16835  else
16836  {
16837  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
16838  {
16839  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
16840  ReturnFlag = InRouteFalse;
16841  Utilities->CallLogPop(341);
16842  return;
16843  }
16844  }
16845  }
16846  int RouteNumber;
16848 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
16849 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
16850 
16851 // check if part of this route already locked & disallow if so
16852  if(!(AllRoutes->LockedRouteVector.empty()))
16853  {
16855  {
16856  if(LRVIT->RouteNumber == RouteNumber)
16857  {
16858  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
16859  ReturnFlag = InRouteFalse;
16860  Utilities->CallLogPop(749);
16861  return;
16862  }
16863  }
16864  }
16865  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
16866  // RouteLockingRequired only checks for trains approaching
16867  {
16870  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
16871  L"Warning!", MB_YESNO | MB_ICONWARNING);
16872  TrainController->BaseTime = TDateTime::CurrentDateTime();
16874  if(button == IDNO)
16875  {
16876  ReturnFlag = InRouteTrue; // still return true even though don't act on it
16877  Utilities->CallLogPop(342);
16878  return;
16879  }
16880  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
16881  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
16882  TAllRoutes::TLockedRouteClass LockedRoute;
16883  bool ExistingLockedRouteModified = false;
16884  LockedRoute.RouteNumber = RouteNumber;
16885  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
16886  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
16887  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
16888  LockedRoute.LockStartTime = TrainController->TTClockTime;
16889 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
16890 // to use the new TruncateTrackVectorPosition & LockStartTime
16891  if(!AllRoutes->LockedRouteVector.empty())
16892  {
16893  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
16894  LRVIT++)
16895  {
16896  if(LRVIT->RouteNumber == RouteNumber)
16897  {
16898  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
16899  LRVIT->LockStartTime = LockedRoute.LockStartTime;
16900  ExistingLockedRouteModified = true;
16901  }
16902  }
16903  }
16904  if(!ExistingLockedRouteModified)
16905  {
16906  AllRoutes->LockedRouteVector.push_back(LockedRoute);
16907  }
16908  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
16909  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
16910  {
16911  // return all signals to red in route section to be truncated
16912  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
16913  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
16914  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16915  {
16916  TrackElement.Attribute = 0;
16917  Track->PlotSignal(2, TrackElement, Display);
16918  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16919  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16920  }
16921  }
16922 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
16923  ReturnFlag = InRouteTrue;
16924  }
16925  else
16926  {
16927  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
16928  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
16929  {
16930  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
16931  ReturnFlag = InRouteTrue;
16932  }
16933  }
16934  AllRoutes->CheckMapAndRoutes(5); // test
16935  Utilities->CallLogPop(343);
16936  return;
16937  }
16938  }
16939  ReturnFlag = NotInRoute;
16940  Utilities->CallLogPop(344);
16941 }
16942 
16943 // ---------------------------------------------------------------------------
16945 /*
16946  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
16947  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
16948  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
16949  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
16950  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
16951  the route colours.
16952 */
16953 {
16954  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
16955  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
16957  int RouteNumber;
16958  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
16959  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
16960 
16961  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
16962  {
16963  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
16964  {
16965  if(PrefDirVector.at(x).TrackType == SignalPost)
16966  {
16967  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
16968  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
16969  }
16970  }
16971  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
16972 // already set all signals to red in route so start at start of route for further rearwards signal setting
16973  }
16974  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
16975  {
16976  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
16977  }
16978  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
16979  AllRoutes->CheckMapAndRoutes(9); // test
16980  TrainController->BaseTime = TDateTime::CurrentDateTime();
16982  Utilities->CallLogPop(345);
16983  return;
16984 }
16985 
16986 // ---------------------------------------------------------------------------
16987 
16988 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
16989 /*
16990  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
16991 */
16992 {
16993  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
16994  AnsiString((short)PrefDirRoute));
16995  if(SearchVector.empty())
16996  {
16997  Utilities->CallLogPop(1149);
16998  return;
16999  }
17000  for(unsigned int b = 0; b < SearchVector.size(); b++)
17001  {
17004  PrefDirRoute);
17005  }
17006  Utilities->CallLogPop(346);
17007 }
17008 
17009 // ---------------------------------------------------------------------------
17010 
17011 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17012 /*
17013  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17014  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17015  TOneRoute.
17016 */
17017 {
17018  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17019  AnsiString((short)PrefDirRoute));
17020  RouteFlash.RouteFlashVector.clear();
17021  TRouteFlashElement RouteFlashElement;
17022 
17023  for(unsigned int b = 0; b < SearchVector.size(); b++)
17024  {
17025  int H = GetFixedSearchElementAt(11, b).HLoc;
17026  int V = GetFixedSearchElementAt(12, b).VLoc;
17028  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17029  RouteFlashElement.HLoc = H;
17030  RouteFlashElement.VLoc = V;
17032  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17033  }
17034  Utilities->CallLogPop(348);
17035 }
17036 
17037 // ---------------------------------------------------------------------------
17038 
17039 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17040 {
17041  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17042  if(!PrefDirVector.empty())
17043  {
17044  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17045  {
17046  int H = PrefDirPtr->HLoc;
17047  int V = PrefDirPtr->VLoc;
17048  // check for any LCs that are closed to trains & set the flash values and store in the vector
17049  if(Track->IsLCAtHV(39, H, V))
17050  {
17051  if(Track->IsLCBarrierUpAtHV(0, H, V))
17052  {
17053  Track->LCChangeFlag = true;
17054  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17055  CLC.HLoc = H;
17056  CLC.VLoc = V;
17058  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17061  if(PrefDirRoute)
17062  {
17063  CLC.TypeOfRoute = 1;
17064  }
17065  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17066  Track->ChangingLCVector.push_back(CLC);
17067  }
17068  }
17069  }
17070  }
17071  Utilities->CallLogPop(1948);
17072 }
17073 
17074 // ---------------------------------------------------------------------------
17075 
17077 /*
17078  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17079  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17080  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17081  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17082 */
17083 {
17084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17085  if(!OverlayPlotted)
17086  {
17087  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17088  {
17089  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17090  {
17091  continue;
17092  }
17093  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17094  Display->Update();
17095  }
17096  OverlayPlotted = true;
17097  }
17098  Utilities->CallLogPop(349);
17099 }
17100 
17101 // ---------------------------------------------------------------------------
17102 
17104 /*
17105  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17106  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17107  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17108  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17109 */
17110 {
17111  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17112  if(OverlayPlotted)
17113  {
17114  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17115  {
17116  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17117  {
17118  continue;
17119  }
17120  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17121  Display->Update();
17122  }
17123  OverlayPlotted = false;
17124  }
17125  Utilities->CallLogPop(350);
17126 }
17127 
17128 // ---------------------------------------------------------------------------
17129 
17130 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17131 {
17132  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17133  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17134  {
17135  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17136  }
17137  Utilities->CallLogPop(120);
17138  return(AllRoutesVector.at(At));
17139 }
17140 
17141 // ---------------------------------------------------------------------------
17142 // ---------------------------------------------------------------------------
17143 
17145 {
17146  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17147  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17148  {
17149  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17150  }
17151  Utilities->CallLogPop(121);
17152  return(AllRoutesVector.at(At));
17153 }
17154 
17155 // ---------------------------------------------------------------------------
17156 
17157 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17158 /*
17159  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17160 */
17161 {
17162  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17163  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17164  {
17165  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17166  }
17167  Utilities->CallLogPop(351);
17168 }
17169 
17170 // ---------------------------------------------------------------------------
17171 
17172 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17173 {
17174  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17175  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17176  {
17177  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17178  }
17179  Utilities->CallLogPop(1706);
17180 }
17181 
17182 // ---------------------------------------------------------------------------
17183 
17184 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17185 /*
17186  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17187  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17188  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17189  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17190  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17191  length (train length).
17192 */
17193 {
17194  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17195  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17196  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17197  {
17198  TTruncateReturnType ReturnFlag;
17199  RouteTruncateFlag = true;
17200 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17201  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17202  RouteTruncateFlag = false;
17203  if(ReturnFlag == NotInRoute)
17204  {
17205  continue;
17206  }
17207  else if(ReturnFlag == InRouteTrue)
17208  {
17209  Utilities->CallLogPop(352);
17210  return(true);
17211  }
17212  else if(ReturnFlag == InRouteFalse)
17213  {
17214  Utilities->CallLogPop(353);
17215  return(false);
17216  }
17217  }
17218  Utilities->CallLogPop(354);
17219  return(false);
17220 }
17221 
17222 // ---------------------------------------------------------------------------
17223 
17224 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17225 /*
17226  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17227  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17228 */
17229 {
17230  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17231  AnsiString(LinkPos));
17232  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17233  {
17234  Utilities->CallLogPop(355);
17235  return(false);
17236  }
17237  THVPair Route2MultiMapKeyPair;
17238 
17239  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17240  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17241  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17242  TRoute2MultiMapIterator Route2MultiMapIterator;
17243 
17244  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17245  {
17246  Utilities->CallLogPop(356);
17247  return(false);
17248  }
17249  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17250  {
17251  Utilities->CallLogPop(1422);
17252  return(true);
17253  }
17254  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17255  {
17256  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17257 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17258 // realised after writing this that can't be points as would have been covered above, but leave anyway
17259  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17260  Route2MultiMapIterator->second.second);
17261  EntryLinkPos = PrefDirElement1.ELinkPos;
17262  ExitLinkPos = PrefDirElement1.XLinkPos;
17263  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17264  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17265  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17266  {
17267  Utilities->CallLogPop(357);
17268  return(true);
17269  }
17270  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17271  {
17272  Utilities->CallLogPop(358);
17273  return(true);
17274  }
17275  }
17276  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17277  {
17278  Utilities->CallLogPop(1423);
17279  return(true);
17280  }
17281  Utilities->CallLogPop(363);
17282  return(false); // none found
17283 }
17284 
17285 // ---------------------------------------------------------------------------
17286 
17287 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17288  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17289 /*
17290  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17291  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17292  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17293  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17294  for replotting of AutoSigsRoutes.
17295 */
17296 {
17297  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17298  AnsiString(LinkPos));
17299  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17300  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17301  if(TrackVectorPosition == -1)
17302  {
17303  Utilities->CallLogPop(364);
17304  return(NoRoute); // allows for continuation entries & exits
17305  }
17306  THVPair Route2MultiMapKeyPair;
17307 
17308  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17309  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17310  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17311  TRoute2MultiMapIterator Route2MultiMapIterator;
17312 
17313  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17314  {
17315  Utilities->CallLogPop(365);
17316  return(NoRoute); // none found
17317  }
17318  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17319  {
17320  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17321 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17322  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17323  Route2MultiMapIterator->second.second);
17324  EntryLinkPos = PrefDirElement1.ELinkPos;
17325  ExitLinkPos = PrefDirElement1.XLinkPos;
17326  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17327  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17328  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17329  {
17330  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17331  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17332  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17333  {
17334  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17335  }
17336  if(PrefDirElement1.AutoSignals)
17337  {
17338  Utilities->CallLogPop(366);
17339  return(AutoSigsRoute);
17340  }
17341  else
17342  {
17343  Utilities->CallLogPop(367);
17344  return(NotAutoSigsRoute);
17345  }
17346  }
17347  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17348  {
17349  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17350  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17351  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17352  {
17353  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17354  }
17355  if(PrefDirElement1.AutoSignals)
17356  {
17357  Utilities->CallLogPop(368);
17358  return(AutoSigsRoute);
17359  }
17360  else
17361  {
17362  Utilities->CallLogPop(369);
17363  return(NotAutoSigsRoute);
17364  }
17365  }
17366  }
17367  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17368  {
17369  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17370  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17371 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17372  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17373  EntryLinkPos = PrefDirElement2.ELinkPos;
17374  ExitLinkPos = PrefDirElement2.XLinkPos;
17375  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17376  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17377  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17378  {
17379  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17380  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17381  {
17382  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17383  }
17384  if(PrefDirElement2.AutoSignals)
17385  {
17386  Utilities->CallLogPop(370);
17387  return(AutoSigsRoute);
17388  }
17389  else
17390  {
17391  Utilities->CallLogPop(371);
17392  return(NotAutoSigsRoute);
17393  }
17394  }
17395  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17396  {
17397  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17398  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17399  {
17400  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17401  }
17402  if(PrefDirElement2.AutoSignals)
17403  {
17404  Utilities->CallLogPop(372);
17405  return(AutoSigsRoute);
17406  }
17407  else
17408  {
17409  Utilities->CallLogPop(373);
17410  return(NotAutoSigsRoute);
17411  }
17412  }
17413  ItPair.second--; // the second iterator points one past the last matching value
17414  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17415  EntryLinkPos = PrefDirElement3.ELinkPos;
17416  ExitLinkPos = PrefDirElement3.XLinkPos;
17417  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17418  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17419  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17420  {
17421  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17422  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17423  {
17424  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17425  }
17426  if(PrefDirElement3.AutoSignals)
17427  {
17428  Utilities->CallLogPop(374);
17429  return(AutoSigsRoute);
17430  }
17431  else
17432  {
17433  Utilities->CallLogPop(375);
17434  return(NotAutoSigsRoute);
17435  }
17436  }
17437  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17438  {
17439  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17440  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17441  {
17442  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17443  }
17444  if(PrefDirElement3.AutoSignals)
17445  {
17446  Utilities->CallLogPop(376);
17447  return(AutoSigsRoute);
17448  }
17449  else
17450  {
17451  Utilities->CallLogPop(377);
17452  return(NotAutoSigsRoute);
17453  }
17454  }
17455  }
17456  Utilities->CallLogPop(378);
17457  return(NoRoute); // none found
17458 }
17459 
17460 // ---------------------------------------------------------------------------
17461 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17462 /*
17463  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
17464  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
17465 */
17466 {
17467  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
17468  AnsiString(LinkPos));
17469  if(TrackVectorPosition == -1)
17470  {
17471  RouteNumber = -1;
17472  Utilities->CallLogPop(379);
17473  return(NoRoute); // allows for continuation & buffer entries & exits
17474  }
17475  THVPair Route2MultiMapKeyPair;
17476 
17477  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
17478  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
17479  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17480  TRoute2MultiMapIterator Route2MultiMapIterator;
17481 
17482  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17483  {
17484  RouteNumber = -1;
17485  Utilities->CallLogPop(380);
17486  return(NoRoute); // none found
17487  }
17488  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17489  {
17490  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17491 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17492  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
17493  Route2MultiMapIterator->second.second);
17494  EntryLinkPos = PrefDirElement1.ELinkPos;
17495  ExitLinkPos = PrefDirElement1.XLinkPos;
17496  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17497  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17498  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
17499  {
17500  RouteNumber = Route2MultiMapIterator->second.first;
17501  if(PrefDirElement1.AutoSignals)
17502  {
17503  Utilities->CallLogPop(381);
17504  return(AutoSigsRoute);
17505  }
17506  else
17507  {
17508  Utilities->CallLogPop(382);
17509  return(NotAutoSigsRoute);
17510  }
17511  }
17512  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
17513  {
17514  RouteNumber = Route2MultiMapIterator->second.first;
17515  if(PrefDirElement1.AutoSignals)
17516  {
17517  Utilities->CallLogPop(383);
17518  return(AutoSigsRoute);
17519  }
17520  else
17521  {
17522  Utilities->CallLogPop(384);
17523  return(NotAutoSigsRoute);
17524  }
17525  }
17526  }
17527  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17528  {
17529  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17530  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17531 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17532  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
17533  EntryLinkPos = PrefDirElement2.ELinkPos;
17534  ExitLinkPos = PrefDirElement2.XLinkPos;
17535  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17536  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17537  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
17538  {
17539  RouteNumber = ItPair.first->second.first;
17540  if(PrefDirElement2.AutoSignals)
17541  {
17542  Utilities->CallLogPop(385);
17543  return(AutoSigsRoute);
17544  }
17545  else
17546  {
17547  Utilities->CallLogPop(386);
17548  return(NotAutoSigsRoute);
17549  }
17550  }
17551  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
17552  {
17553  RouteNumber = ItPair.first->second.first;
17554  if(PrefDirElement2.AutoSignals)
17555  {
17556  Utilities->CallLogPop(387);
17557  return(AutoSigsRoute);
17558  }
17559  else
17560  {
17561  Utilities->CallLogPop(388);
17562  return(NotAutoSigsRoute);
17563  }
17564  }
17565  ItPair.second--; // the second iterator points one past the last matching value
17566  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
17567  EntryLinkPos = PrefDirElement3.ELinkPos;
17568  ExitLinkPos = PrefDirElement3.XLinkPos;
17569  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17570  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17571  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
17572  {
17573  RouteNumber = ItPair.second->second.first;
17574  if(PrefDirElement3.AutoSignals)
17575  {
17576  Utilities->CallLogPop(389);
17577  return(AutoSigsRoute);
17578  }
17579  else
17580  {
17581  Utilities->CallLogPop(390);
17582  return(NotAutoSigsRoute);
17583  }
17584  }
17585  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
17586  {
17587  RouteNumber = ItPair.second->second.first;
17588  if(PrefDirElement3.AutoSignals)
17589  {
17590  Utilities->CallLogPop(391);
17591  return(AutoSigsRoute);
17592  }
17593  else
17594  {
17595  Utilities->CallLogPop(392);
17596  return(NotAutoSigsRoute);
17597  }
17598  }
17599  }
17600  RouteNumber = -1;
17601  Utilities->CallLogPop(393);
17602  return(NoRoute); // none found
17603 }
17604 
17605 // ---------------------------------------------------------------------------
17606 
17607 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
17608 /*
17609  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
17610  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
17611  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
17612  and Route2MultiMap.
17613 */
17614 {
17615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
17616  TOneRoute EmptyRoute;
17617 
17618  EmptyRoute.RouteID = NextRouteID;
17619  NextRouteID++;
17620 
17621  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17622  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17623  {
17624  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
17625  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
17626  }
17627  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
17628  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
17629 
17630  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
17631  Utilities->CallLogPop(394);
17632 }
17633 
17634 // ---------------------------------------------------------------------------
17635 
17637 /*
17638  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
17639  that is already in Route is used.
17640 */
17641 {
17642  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
17643  TOneRoute EmptyRoute;
17644 
17645  EmptyRoute.RouteID = Route->RouteID;
17646 
17647  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17648  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17649  {
17650  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
17651  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
17652  }
17653  Utilities->CallLogPop(1579);
17654 }
17655 
17656 // ---------------------------------------------------------------------------
17657 
17658 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
17659 /*
17660  When attaching a new route section to an existing route, it is sometimes necessary to erase the
17661  original route and create a new composite route. This function Erases all elements in the route
17662  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
17663  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
17664  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
17665  that are greater than the route number that is removed. The LockedRouteVector as also searched
17666  and if any relate to the route that has been cleared they are erased too, but the fact that one
17667  has been found is recorded so that it can be re-established later.
17668 */
17669 {
17670  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
17671  THVPair Route2MultiMapKeyPair;
17672  TRoute2MultiMapEntry Route2MultiMapEntry;
17673  TRoute2MultiMapIterator Route2MultiMapIterator;
17674 
17675 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
17676 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
17677 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
17678 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
17679 // If so the locked route is removed from the locked vector and is lost.
17680  LockedRouteTruncateTrackVectorPosition = 0;
17681  LockedRouteLastTrackVectorPosition = 0;
17682  LockedRouteLastXLinkPos = 0;
17683  LockedRouteLockStartTime = TDateTime(0);
17684  if(!LockedRouteVector.empty())
17685  {
17686  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
17687  {
17688  if(LRVIT->RouteNumber == RouteNumber)
17689  {
17690  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
17691  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
17692  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
17693  LockedRouteLockStartTime = LRVIT->LockStartTime;
17694  LockedRouteFoundDuringRouteBuilding = true;
17695  LockedRouteVector.erase(LRVIT);
17696  }
17697  }
17698  }
17699  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
17700  {
17701  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
17702  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
17703  }
17704  Utilities->CallLogPop(395);
17705 }
17706 
17707 // ---------------------------------------------------------------------------
17708 
17710  TRoute2MultiMapIterator &Route2MultiMapIterator)
17711 /*
17712  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
17713  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
17714  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
17715  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
17716  are given for failure.
17717 */
17718 {
17719  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
17720  AnsiString(VLoc) + "," + AnsiString(ELink));
17721  TRouteElementPair ReturnPair;
17722 
17723  ReturnPair.first = -1;
17724  ReturnPair.second = 0;
17725  THVPair Route2MultiMapKeyPair;
17726 
17727  Route2MultiMapKeyPair.first = HLoc;
17728  Route2MultiMapKeyPair.second = VLoc;
17729  TRoute2MultiMapEntry Route2MultiMapEntry;
17730 
17731  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
17732  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17733 
17734  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17735  Route2MultiMapIterator = ItPair.first;
17736 
17737  if(ItPair.first == ItPair.second)
17738  {
17739  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
17740  }
17741  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
17742  {
17743  ReturnPair.first = ItPair.first->second.first;
17744  ReturnPair.second = ItPair.first->second.second;
17745  Route2MultiMapIterator = ItPair.first;
17746  Utilities->CallLogPop(396);
17747  return(ReturnPair);
17748  }
17749  ItPair.first++;
17750  if(ItPair.first == ItPair.second)
17751  {
17752  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
17753  }
17754  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
17755  {
17756  ReturnPair.first = ItPair.first->second.first;
17757  ReturnPair.second = ItPair.first->second.second;
17758  Route2MultiMapIterator = ItPair.first;
17759  Utilities->CallLogPop(397);
17760  return(ReturnPair);
17761  }
17762  Utilities->CallLogPop(398);
17763  return(ReturnPair);
17764 }
17765 
17766 // ---------------------------------------------------------------------------
17767 
17768 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
17769 /*
17770  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
17771  Examines Route2MultiMap and returns true if oa route is found with the passed values of H, V and ELink.
17772  RouteNumber (route position in AllRoutes vector is returned as a reference.
17773  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
17774  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
17775 */
17776 {
17777  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
17778  AnsiString(VLoc) + "," + AnsiString(ELink));
17779  THVPair Route2MultiMapKeyPair;
17780 
17781  Route2MultiMapKeyPair.first = HLoc;
17782  Route2MultiMapKeyPair.second = VLoc;
17783  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17784 
17785  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17786 
17787  if(ItPair.first == ItPair.second)
17788  {
17789  RouteNumber = -1;
17790  Utilities->CallLogPop(2032);
17791  return(false);
17792  }
17793  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
17794  {
17795  RouteNumber = ItPair.first->second.first;
17796  Utilities->CallLogPop(2033);
17797  return(true);
17798  }
17799  ItPair.first++;
17800 
17801  if(ItPair.first == ItPair.second)
17802  {
17803  RouteNumber = -1;
17804  Utilities->CallLogPop(2034);
17805  return(false);
17806  }
17807  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
17808  {
17809  RouteNumber = ItPair.first->second.first;
17810  Utilities->CallLogPop(2035);
17811  return(true);
17812  }
17813  RouteNumber = -1;
17814  Utilities->CallLogPop(2036);
17815  return(false);
17816 }
17817 
17818 // ---------------------------------------------------------------------------
17819 
17820 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
17821 /*
17822  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
17823  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
17824  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
17825  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
17826  Called by TAllRoutes::AddRouteElement.
17827 */
17828 {
17829  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17830  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
17831  THVPair Route2MultiMapKeyPair;
17832 
17833  Route2MultiMapKeyPair.first = HLoc;
17834  Route2MultiMapKeyPair.second = VLoc;
17835  TRoute2MultiMapEntry Route2MultiMapEntry;
17836 
17837  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
17838  TRouteElementPair RouteElementPair;
17839 
17840  RouteElementPair.first = RouteNumber;
17841  RouteElementPair.second = RouteElementNumber;
17842  Route2MultiMapEntry.second = RouteElementPair;
17843 
17844  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
17845  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
17846  {
17847  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
17848  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
17849  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
17850  {
17851  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
17852  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
17853  {
17854  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
17855  }
17856  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
17857  }
17858  else
17859  // same ELink so have an error
17860  {
17861  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
17862  }
17863  }
17864  else
17865  {
17866  Route2MultiMap.insert(Route2MultiMapEntry);
17867  }
17868 // element at H&V not found in map so insert it
17869  Utilities->CallLogPop(399);
17870 }
17871 
17872 // ---------------------------------------------------------------------------
17873 
17875 /*
17876  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
17877  and the second in the reference SecondPair. If there's only one then it's the function return
17878 */
17879 {
17880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
17881  AnsiString(VLoc));
17883 
17884  TempPair.first = -1;
17885  TempPair.second = 0;
17886  SecondPair = TempPair;
17887  TRoute2MultiMapIterator Route2MultiMapIterator;
17888  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
17889  THVPair Route2MultiMapKeyPair;
17890 
17891  Route2MultiMapKeyPair.first = HLoc;
17892  Route2MultiMapKeyPair.second = VLoc;
17893  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17894  {
17895  Utilities->CallLogPop(400);
17896  return(TempPair);
17897  }
17898  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17899  {
17900  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17901  Utilities->CallLogPop(401);
17902  return(Route2MultiMapIterator->second);
17903  }
17904  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17905  {
17906  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17907  TempPair = ItRange.first->second;
17908  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
17909  Utilities->CallLogPop(402);
17910  return(TempPair);
17911  }
17912  Utilities->CallLogPop(403);
17913  return(TempPair);
17914 }
17915 
17916 // ---------------------------------------------------------------------------
17917 
17918 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
17919 /*
17920  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
17921  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
17922 */
17923 {
17924  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
17925  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
17926  {
17927  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
17928  {
17929  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
17930  TAllRoutes::TRouteElementPair SecondPair;
17931  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
17932  if(RouteElementPair.first == -1)
17933  // failed to find element in multimap
17934  {
17935  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
17936  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
17937  }
17938  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
17939  // neither pair has expected route number
17940  {
17941  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
17942  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
17943  (AnsiString)Caller);
17944  }
17945  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
17946  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
17947  {
17948  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
17949  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
17950  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
17951  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
17952  }
17953  }
17954  }
17955  unsigned int SizeVal = 0;
17956 
17957 // check map and sum of route sizes match
17958  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17959  {
17960  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
17961  }
17962  if(SizeVal != Route2MultiMap.size())
17963  {
17964  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
17965  (AnsiString)Caller);
17966  }
17967  Utilities->CallLogPop(404);
17968  return;
17969 }
17970 
17971 // ---------------------------------------------------------------------------
17972 
17973 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
17974 /*
17975  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
17976  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
17977  exceed that for the erased route. Where this is so the RouteNumber is decremented.
17978 */
17979 {
17980  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
17981  if(!Route2MultiMap.empty())
17982  {
17983  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
17984  {
17985  if(Route2MultiMapIterator->second.first > RouteNumber)
17986  {
17987  Route2MultiMapIterator->second.first--;
17988  }
17989  }
17990  }
17991  Utilities->CallLogPop(405);
17992 }
17993 
17994 // ---------------------------------------------------------------------------
17995 
17996 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
17997 /*
17998  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
17999  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18000  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18001 */
18002 {
18003  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18004  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18005  if(!Route2MultiMap.empty())
18006  {
18007  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18008  {
18009  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18010  {
18011  Route2MultiMapIterator->second.second--;
18012  }
18013  }
18014  }
18015  Utilities->CallLogPop(406);
18016 }
18017 
18018 // ---------------------------------------------------------------------------
18019 
18020 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18021 /*
18022  Erases the route element from Route2MultiMap and from the PrefDirVector.
18023  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18024  decremented if they are greater than the element number removed, and if the entire route is removed
18025  then the route numbers are also decremented in the map for route numbers that are greater than the route
18026  number that is removed.
18027 */
18028 {
18029  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18030  AnsiString(ELink));
18031  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18032  TRoute2MultiMapIterator Route2MultiMapIterator;
18033 
18034  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18035  if(RequiredRoutePair.first == -1)
18036  {
18037  throw Exception("Failed to find route element in RemoveRouteElement");
18038  }
18039  Route2MultiMap.erase(Route2MultiMapIterator);
18040  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18041 
18042 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18043  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18044 
18045  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18046  {
18047  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18048  }
18049 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18050 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18051 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18052 // to check if a route element is present, and the element has already been removed from the map - see above.
18053 
18054 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18055 /*
18056  int LockedVectorNumber = -1;
18057  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18058  {
18059  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18060  }
18061 */
18062 
18063 // erase element from route
18064  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18065  RequiredRoutePair.second)));
18066 // CheckMapAndRoutes();//test - drop - tested below
18067 
18068 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18069 // be so as continuation exit is at the end of the route, and truncation is from the end
18071  {
18073  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18074  AutoSigVectorIT--)
18075  {
18076  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18077  {
18078  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18079  }
18080  }
18081  }
18082 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18083 // and adjust all the corresponding route numbers
18084  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18085  {
18086  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18087  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18088  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18089 
18090 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18091  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18092  it is erased then - see TInterface::ApproachLocking
18093 
18094  if(LockedVectorNumber > -1)
18095  {
18096  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18097  }
18098 */
18099  // decrement route numbers in the locked route vector whether or not this route is a locked route
18100  if(!LockedRouteVector.empty())
18101  {
18102  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18103  {
18104  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18105  {
18106  LRVIT->RouteNumber--;
18107  }
18108  }
18109  }
18111  {
18113  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18114  AutoSigVectorIT--)
18115  {
18116  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18117  {
18118  AutoSigVectorIT->RouteNumber--;
18119  }
18120  }
18121  }
18122  }
18123  CheckMapAndRoutes(7); // test
18124  Utilities->CallLogPop(407);
18125 }
18126 
18127 // ---------------------------------------------------------------------------
18128 
18129 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18130 /*
18131  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18132  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18133  since that catches all route elements wherever created
18134 */
18135 {
18136  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18137  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18138  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18139  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18140  Utilities->CallLogPop(408);
18141 }
18142 
18143 // ---------------------------------------------------------------------------
18144 
18145 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18146 /*
18147  Enter with signal at TrackVectorElement already set to red by the passing train.
18148  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18149  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18150  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18151  case the function sets no further signals.
18152 */
18153 {
18154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18155  "," + AnsiString(XLinkPos));
18156  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18157  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18158 
18159  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18160  if(RouteElementPair.first == -1)
18161  {
18162  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18163  }
18164  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18165 
18166  RequiredPair = RouteElementPair;
18167  if(RouteElement.XLinkPos != XLinkPos)
18168  {
18169  if(SecondPair.first != -1)
18170  {
18171  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18172  RequiredPair = SecondPair;
18173  if(RouteElement.XLinkPos != XLinkPos)
18174  {
18175  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18176  }
18177  }
18178  else
18179  {
18180  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18181  }
18182  }
18183 // new function
18184  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18185  Utilities->CallLogPop(409);
18186 }
18187 
18188 // ---------------------------------------------------------------------------
18189 
18190 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18191 /*
18192  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18193  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18194  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18195  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18196  to 2 for successive calls.
18197  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18198  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18199  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18200  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18201 */
18202 {
18203  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18204  AnsiString(AccessNumber));
18205  TPrefDirElement RouteElement;
18206  int Attribute = AccessNumber + 1;
18207 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18208  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18209 
18210  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18211  {
18212  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18213  }
18214  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18215  {
18216  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18217  }
18218  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18219  x).XLinkPos] != End)
18220  {
18221  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18222  }
18223 // new function
18224  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18225  Utilities->CallLogPop(410);
18226 }
18227 
18228 // ---------------------------------------------------------------------------
18229 
18230 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18231 /*
18232  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18233  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18234  or (b) in a linked rear route, in which case the function sets no further signals.
18235 
18236  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18237  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18238  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18239  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18240  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18241  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18242  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18243  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18244  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18245  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18246  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18247  found behind the train.
18248 
18249  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18250  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18251  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18252  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18253  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18254  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18255  a route.
18256 
18257  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18258  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18259  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 and continue working backwards
18260  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18261  reference. If no train is found before the beginning of the route is reached the function returns true.
18262 
18263 */
18264 {
18265  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18266  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18267  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18268  int RearwardLinkedRouteNumber;
18269 
18270  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18271  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18272  // signal value in the route for use in further linked routes
18273  {
18274  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18275  {
18276  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18277  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18278  {
18279  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18280  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18281  {
18282  break;
18283  }
18284  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18285  // flash LCs on those routes
18286  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18287  }
18288  }
18289  }
18290  else
18291  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18292  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18293  {
18294  int TrainID, TrainPosition, BehindTrainPosition;
18295  bool FoundTrain = false, BehindTrain = false;
18296  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18297  {
18298  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18299  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18300  TrainID = TrackElement.TrainIDOnElement;
18301  if(TrackElement.TrackType == Bridge)
18302  {
18303  if(PrefDirElement.XLinkPos < 2)
18304  {
18305  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18306  }
18307  else
18308  {
18309  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18310  }
18311  }
18312  if(TrainID == -1)
18313  {
18314  continue;
18315  }
18316  else
18317  {
18318  FoundTrain = true;
18319  TrainPosition = x;
18320  break;
18321  }
18322  }
18323  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18324  {
18325  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18326  {
18327  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18328  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18329  // need the element behind the rearmost train.
18330  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18331  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18332  TrainID = TrackElement.TrainIDOnElement;
18333  if(TrackElement.TrackType == Bridge)
18334  {
18335  if(PrefDirElement.XLinkPos < 2)
18336  {
18337  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18338  }
18339  else
18340  {
18341  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18342  }
18343  }
18344  if(TrainID != -1)
18345  {
18346  continue; // still on train
18347  }
18348  else
18349  {
18350  BehindTrain = true;
18351  BehindTrainPosition = x;
18352  break;
18353  }
18354  }
18355  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18356  // so on for as many trains as there are on the single route
18357  {
18358  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18359  // first signal behind train to be red
18360  }
18361  }
18362  }
18363  Utilities->CallLogPop(411);
18364 }
18365 
18366 // ---------------------------------------------------------------------------
18367 
18368 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18369 {
18370 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18371  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18372  first signal is red, then OK
18373 */
18374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18375  AnsiString(RouteTruncatePosition));
18376  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18377  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18378  TPrefDirElement PrefDirElement, FirstElement;
18379  TTrackElement TrackElement;
18380  bool ExamineRoute = true;
18381 
18382  while(ExamineRoute)
18383  {
18384  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18385  {
18386  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18387  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18388  TrainID = TrackElement.TrainIDOnElement;
18389  if(TrackElement.TrackType == Bridge)
18390  {
18391  if(PrefDirElement.XLinkPos < 2)
18392  {
18393  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18394  }
18395  else
18396  {
18397  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18398  }
18399  }
18400  if(TrainID > -1)
18401  {
18402  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18403  {
18404  //any trains further back in route will be protected by the red signal behind the stopped train
18405  Utilities->CallLogPop(412);
18406  return(false);
18407  }
18408  //added after v2.4.1 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18409  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18410  //other way & can cancel the route
18411  {
18412  Utilities->CallLogPop(2203);
18413  return(false);
18414  }
18415  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18416  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18417  }
18418  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18419  {
18420  if(TrackElement.Attribute == 0)
18421  {
18422  Utilities->CallLogPop(413);
18423  return(false); // OK, red signal in front of a train
18424  }
18425  SignalCount++;
18426  if(SignalCount >= 3)
18427  {
18428  Utilities->CallLogPop(414);
18429  return(false);
18430  }
18431  }
18432  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18433  // ElinkPos because working back along PrefDir to beginning
18434  {
18435  Utilities->CallLogPop(415);
18436  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18437  }
18438  }
18439  //now look at linked rearwards routes
18440  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18441  StartPosition = CurrentRoute.PrefDirSize() - 1;
18442  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18443  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18444  {
18445  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18446  ExamineRoute = true;
18447  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18448  }
18449  else
18450  {
18451  // here check for a train on the element immediately before the first route element
18452  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18453  TrainID = PriorTrackElement.TrainIDOnElement;
18454  if(PriorTrackElement.TrackType == Bridge)
18455  {
18456  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18457  {
18458  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18459  }
18460  else
18461  {
18462  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
18463  }
18464  }
18465  if(TrainID > -1)
18466  {
18467  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
18468  {
18469  Utilities->CallLogPop(748);
18470  return(false);
18471  }
18472  //added after v2.4.1 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
18473  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
18474  //other way & can cancel the route
18475  {
18476  Utilities->CallLogPop(2204);
18477  return(false);
18478  }
18479  Utilities->CallLogPop(1962);
18480  return(true); //otherwise need to lock the route
18481  }
18482  ExamineRoute = false;
18483  }
18484  }
18485 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
18486 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
18487  Utilities->CallLogPop(416);
18488  return(false);
18489 }
18490 
18491 // ---------------------------------------------------------------------------
18492 
18493 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
18494  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
18495 {
18496  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
18497  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
18498  TPrefDirElement InternalPrefDirElement; // blank element
18499 
18500  PrefDirElement = InternalPrefDirElement;
18501  if(LockedRouteVector.empty())
18502  {
18503  Utilities->CallLogPop(417);
18504  return(false);
18505  }
18506 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
18507 // even if some elements have been removed from the front by a train
18508  bool InLockedRoute = false;
18509 
18510  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18511  {
18512  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
18513  {
18514  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
18515  // doesn't arise)
18516  InLockedRoute = true;
18517  break;
18518  }
18519  }
18520  if(!InLockedRoute)
18521  {
18522  Utilities->CallLogPop(418);
18523  return(false);
18524  }
18525  int RouteNumber, VectorCount = 0;
18526  TRouteType RouteType;
18527 
18528  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18529  {
18530  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
18531  if(RouteType == NoRoute)
18532  {
18533  continue;
18534  }
18535  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
18536  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
18537  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
18538  {
18539  throw Exception
18540  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
18541  }
18542  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
18543  {
18544  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
18545  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
18546  {
18547  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18548  {
18549  PrefDirElement = InternalPrefDirElement;
18550  LockedVectorNumber = VectorCount;
18551  Utilities->CallLogPop(419);
18552  return(true);
18553  }
18554  }
18555  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
18556  {
18557  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18558  {
18559  PrefDirElement = InternalPrefDirElement;
18560  LockedVectorNumber = VectorCount;
18561  Utilities->CallLogPop(420);
18562  return(true);
18563  }
18564  else
18565  {
18566  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
18567  }
18568  }
18569  }
18570  VectorCount++;
18571  }
18572  Utilities->CallLogPop(421);
18573  return(false);
18574 }
18575 
18576 // ---------------------------------------------------------------------------
18577 
18579 {
18580  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
18581  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18582  {
18583  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
18584  {
18585  Utilities->CallLogPop(963);
18586  return(x);
18587  }
18588  }
18589  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
18590 }
18591 
18592 // ---------------------------------------------------------------------------
18593 
18595 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
18596 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
18597 {
18598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18599  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18600  {
18601  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
18602  {
18603  Utilities->CallLogPop(2039);
18604  return(true);
18605  }
18606  }
18607  Utilities->CallLogPop(2040);
18608  return(false);
18609 }
18610 
18611 // ---------------------------------------------------------------------------
18612 
18614 {
18615  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18616  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18617  {
18618  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
18619  {
18620  Utilities->CallLogPop(964);
18621  return(GetFixedRouteAt(159, x));
18622  }
18623  }
18624  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18625 }
18626 
18627 // ---------------------------------------------------------------------------
18628 
18630 {
18631  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
18632  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18633  {
18634  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
18635  {
18636  Utilities->CallLogPop(965);
18637  return(GetModifiableRouteAt(15, x));
18638  }
18639  }
18640  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18641 }
18642 
18643 // ---------------------------------------------------------------------------
18644 
18645 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
18646 {
18647  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
18648  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
18649  Utilities->SaveFileInt(OutFile, NextRouteID);
18650  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18651  {
18652  TOneRoute OneRoute = GetFixedRouteAt(165, x);
18653  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
18654  OneRoute.SavePrefDirVector(6, OutFile);
18655  }
18656  Utilities->CallLogPop(1442);
18657 }
18658 
18659 // ---------------------------------------------------------------------------
18660 
18661 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
18662 {
18663  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
18664  int NumberOfRoutes;
18665 
18666  NumberOfRoutes = Utilities->LoadFileInt(InFile);
18667  NextRouteID = Utilities->LoadFileInt(InFile);
18668  for(int x = 0; x < NumberOfRoutes; x++)
18669  {
18670  TOneRoute OneRoute; // empty route
18671  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
18672  OneRoute.LoadPrefDir(2, InFile);
18674  {
18675  StoreOneRouteAfterSessionLoad(0, &OneRoute);
18676  }
18677  else
18678  {
18679  Utilities->CallLogPop(1443);
18680  return(false);
18681  }
18682  }
18683  Utilities->CallLogPop(1444);
18684  return(true);
18685 }
18686 
18687 // ---------------------------------------------------------------------------
18688 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
18689 {
18690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
18691  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
18692 
18693  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
18694  {
18695  Utilities->CallLogPop(1445);
18696  return(false);
18697  }
18698  int NextID = Utilities->LoadFileInt(InFile);
18699 
18700  if((NextID < 0) || (NextID > 1000000))
18701  {
18702  Utilities->CallLogPop(1446);
18703  return(false);
18704  }
18705  for(int x = 0; x < NumberOfRoutes; x++)
18706  {
18707  int RouteID = Utilities->LoadFileInt(InFile);
18708  if((RouteID < 0) || (RouteID > 20000))
18709  {
18710  Utilities->CallLogPop(1447);
18711  return(false);
18712  }
18713  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
18714  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
18715  {
18716  Utilities->CallLogPop(1448);
18717  return(false);
18718  }
18719  }
18720  Utilities->CallLogPop(1449);
18721  return(true);
18722 }
18723 
18724 // ---------------------------------------------------------------------------
18725 
18726 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
18727 {
18728  // return true for a loop
18729  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
18730  AnsiString(StartPosition));
18731  if(EndPosition == StartPosition)
18732  {
18733  Utilities->CallLogPop(1839);
18734  return(true); // shouldn't happen but treat as a loop if does
18735  }
18736 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
18737  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
18738  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
18739 
18740  while(TrackIsInARoute(15, TVPos, LkPos))
18741  {
18742  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
18743  int NewLkPos = -1;
18744  if(NewTVPos > -1)
18745  {
18746  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
18747  if(NewLkPos == -1)
18748  {
18749  Utilities->CallLogPop(1840);
18750  return(true); // shouldn't arise but treat as loop if does
18751  }
18752  }
18753  else // reached a buffer or continuation
18754  {
18755  Utilities->CallLogPop(1841);
18756  return(false);
18757  }
18758 //Error found by Xeon notified by email 13/10/20.
18759 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
18760 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
18761 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
18762 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
18763 //New check added for v2.6.0
18764 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
18765 //as possible in case there are other unforeseen effects.
18766  int RouteNumber; //dummy, not used
18767  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
18768  {
18769  Utilities->CallLogPop(2241);
18770  return(false);
18771  }
18772  //now make the connected element the current element, read across the TV number and determine the exit link
18773  TVPos = NewTVPos;
18774  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
18775  {
18776  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
18777  {
18778  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
18779  {
18780  LkPos = 1;
18781  }
18782  else
18783  {
18784  LkPos = 3;
18785  }
18786  }
18787  else
18788  {
18789  LkPos = 0;
18790  }
18791  }
18792  else
18793  {
18794  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
18795  }
18796  if(TVPos == StartPosition)
18797  {
18798  Utilities->CallLogPop(1842);
18799  return(true); // it is a loop
18800  }
18801  }
18802  Utilities->CallLogPop(1843);
18803  return(false); // reached end of route so not a loop
18804 }
18805 
18806 // ---------------------------------------------------------------------------
18807 
18808 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
18809 /*
18810  Track geometry allows diagonals to cross without occupying the same track element, so when
18811  route plotting it is necessary to check if there is an existing route or a train on such a crossing
18812  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
18813  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
18814  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
18815  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
18816  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
18817  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
18818  Each of these is examined in turn for each route element in the relevant position.
18819 
18820  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
18821  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
18822  that returns false in all cases (including elements & links not present) except train present.
18823 */
18824 {
18825  int TrainID; // not used in this function
18826 
18827  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
18828  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
18829  TPrefDirElement TempPrefDirElement;
18830  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
18831 
18832  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
18833  if(FirstPair.first > -1)
18834  {
18835  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
18836  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18837  {
18838  Utilities->CallLogPop(310);
18839  return(true);
18840  }
18841  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18842  {
18843  Utilities->CallLogPop(311);
18844  return(true);
18845  }
18846  }
18847  if(SecondPair.first > -1)
18848  {
18849  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
18850  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18851  {
18852  Utilities->CallLogPop(312);
18853  return(true);
18854  }
18855  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18856  {
18857  Utilities->CallLogPop(313);
18858  return(true);
18859  }
18860  }
18861  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
18862  9, TrainID)))
18863  {
18864  Utilities->CallLogPop(1997);
18865  return(true);
18866  }
18867  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
18868  if(FirstPair.first > -1)
18869  {
18870  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
18871  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18872  {
18873  Utilities->CallLogPop(314);
18874  return(true);
18875  }
18876  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18877  {
18878  Utilities->CallLogPop(315);
18879  return(true);
18880  }
18881  }
18882  if(SecondPair.first > -1)
18883  {
18884  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
18885  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18886  {
18887  Utilities->CallLogPop(316);
18888  return(true);
18889  }
18890  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
18891  {
18892  Utilities->CallLogPop(317);
18893  return(true);
18894  }
18895  }
18896  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
18897  9, TrainID)))
18898  {
18899  Utilities->CallLogPop(1998);
18900  return(true);
18901  }
18902  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
18903  if(FirstPair.first > -1)
18904  {
18905  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
18906  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18907  {
18908  Utilities->CallLogPop(318);
18909  return(true);
18910  }
18911  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18912  {
18913  Utilities->CallLogPop(319);
18914  return(true);
18915  }
18916  }
18917  if(SecondPair.first > -1)
18918  {
18919  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
18920  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18921  {
18922  Utilities->CallLogPop(320);
18923  return(true);
18924  }
18925  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
18926  {
18927  Utilities->CallLogPop(321);
18928  return(true);
18929  }
18930  }
18931  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
18932  7, TrainID)))
18933  {
18934  Utilities->CallLogPop(1999);
18935  return(true);
18936  }
18937  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
18938  if(FirstPair.first > -1)
18939  {
18940  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
18941  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18942  {
18943  Utilities->CallLogPop(322);
18944  return(true);
18945  }
18946  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18947  {
18948  Utilities->CallLogPop(323);
18949  return(true);
18950  }
18951  }
18952  if(SecondPair.first > -1)
18953  {
18954  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
18955  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
18956  {
18957  Utilities->CallLogPop(324);
18958  return(true);
18959  }
18960  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18961  {
18962  Utilities->CallLogPop(325);
18963  return(true);
18964  }
18965  }
18966  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
18967  3, TrainID)))
18968  {
18969  Utilities->CallLogPop(2000);
18970  return(true);
18971  }
18972  Utilities->CallLogPop(326);
18973  return(false);
18974 }
18975 
18976 // ---------------------------------------------------------------------------
18977 
18978 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
18979 /*
18980  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
18981  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
18982  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
18983  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
18984  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
18985  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
18986  Each of these is examined in turn for each route element in the relevant position.
18987 */
18988 {
18989  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18990  "," + AnsiString(DiagonalLinkNumber));
18991  TPrefDirElement TempPrefDirElement;
18992  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
18993 
18994  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
18995  if(FirstPair.first > -1)
18996  {
18997  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
18998  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
18999  {
19000  Utilities->CallLogPop(2010);
19001  return(true);
19002  }
19003  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19004  {
19005  Utilities->CallLogPop(2011);
19006  return(true);
19007  }
19008  }
19009  if(SecondPair.first > -1)
19010  {
19011  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19012  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19013  {
19014  Utilities->CallLogPop(2012);
19015  return(true);
19016  }
19017  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19018  {
19019  Utilities->CallLogPop(2013);
19020  return(true);
19021  }
19022  }
19023  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19024  if(FirstPair.first > -1)
19025  {
19026  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19027  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19028  {
19029  Utilities->CallLogPop(2014);
19030  return(true);
19031  }
19032  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19033  {
19034  Utilities->CallLogPop(2015);
19035  return(true);
19036  }
19037  }
19038  if(SecondPair.first > -1)
19039  {
19040  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19041  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19042  {
19043  Utilities->CallLogPop(2016);
19044  return(true);
19045  }
19046  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19047  {
19048  Utilities->CallLogPop(2017);
19049  return(true);
19050  }
19051  }
19052  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19053  if(FirstPair.first > -1)
19054  {
19055  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19056  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19057  {
19058  Utilities->CallLogPop(2018);
19059  return(true);
19060  }
19061  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19062  {
19063  Utilities->CallLogPop(2019);
19064  return(true);
19065  }
19066  }
19067  if(SecondPair.first > -1)
19068  {
19069  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19070  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19071  {
19072  Utilities->CallLogPop(2020);
19073  return(true);
19074  }
19075  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19076  {
19077  Utilities->CallLogPop(2021);
19078  return(true);
19079  }
19080  }
19081  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19082  if(FirstPair.first > -1)
19083  {
19084  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19085  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19086  {
19087  Utilities->CallLogPop(2022);
19088  return(true);
19089  }
19090  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19091  {
19092  Utilities->CallLogPop(2023);
19093  return(true);
19094  }
19095  }
19096  if(SecondPair.first > -1)
19097  {
19098  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19099  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19100  {
19101  Utilities->CallLogPop(2024);
19102  return(true);
19103  }
19104  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19105  {
19106  Utilities->CallLogPop(2025);
19107  return(true);
19108  }
19109  }
19110  Utilities->CallLogPop(2026);
19111  return(false);
19112 }
19113 
19114 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8320
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:677
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17224
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1198
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:916
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11157
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:663
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:730
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:613
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:565
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11130
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:361
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:495
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:875
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5378
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12676
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:772
TFixedTrackPiece
Definition: TrackUnit.h:84
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1599
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:710
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:907
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:17820
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:94
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:791
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:908
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9723
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:793
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18230
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:919
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1251
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:702
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:581
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:702
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:12949
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:759
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:620
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:717
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:359
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12716
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:679
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3620
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:700
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:700
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:297
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7034
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1516
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:16736
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:684
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1579
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:636
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5530
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:6935
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5557
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1401
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:515
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1540
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:826
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:847
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1909
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:914
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10057
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:542
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:16500
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:612
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:905
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:18978
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:361
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1570
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:533
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2733
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:480
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5686
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:728
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:672
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:153
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:7897
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1411
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:571
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:17658
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:763
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:507
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:666
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12455
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7364
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9372
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9101
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13597
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14832
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:566
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17184
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18020
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:857
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:855
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1520
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:873
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12259
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:160
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4355
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3571
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:673
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:831
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1423
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:582
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:760
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:796
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7712
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:367
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:662
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:585
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1026
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4515
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1212
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6218
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10541
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:654
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:868
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3447
Unused
@ Unused
Definition: TrackUnit.h:67
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:587
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:617
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1211
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:705
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18493
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2766
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:770
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:256
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:18688
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:503
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9268
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1578
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1421
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1507
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:223
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:917
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:676
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:365
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3171
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15183
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:777
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:669
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8164
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12521
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:704
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:794
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2782
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:638
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1005
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:17768
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:775
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:819
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1278
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:706
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12771
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1715
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:595
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5646
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:670
TTrain
Definition: TrainUnit.h:279
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:321
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13468
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:155
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11171
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:561
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:499
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:552
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7379
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:67
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:790
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18129
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:856
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7181
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:151
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:920
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:151
TTrack::Raising
@ Raising
Definition: TrackUnit.h:533
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:628
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:497
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10162
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:584
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1425
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1389
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:698
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:649
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:509
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:706
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:761
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:715
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1287
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5878
End
@ End
Definition: TrackUnit.h:77
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1427
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:668
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:843
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:544
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8518
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:864
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:903
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:492
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackElement.at(At)
Definition: TrackUnit.cpp:10270
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1018
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:303
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:800
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:651
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:712
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:578
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:913
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:127
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:723
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:758
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3738
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:989
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:768
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:990
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:260
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:701
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9233
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:999
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17172
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:431
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:778
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1071
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1544
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:792
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:827
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7393
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:593
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6627
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:258
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:685
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8557
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:906
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:817
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17157
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:756
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:515
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:657
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:721
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:801
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:76
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13238
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:12975
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:714
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:821
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:66
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4440
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1859
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:814
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:829
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:594
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:804
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:359
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:686
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:96
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:816
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:575
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:10744
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:17973
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4674
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:160
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1878
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:674
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:789
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:924
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:665
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:487
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:586
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:720
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:835
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:444
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:10989
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:18594
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:515
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1016
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:611
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2750
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:710
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1433
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7350
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14414
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7062
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8354
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7141
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:667
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:721
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:615
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:660
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:292
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:606
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1214
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:768
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:803
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:802
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:12859
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:766
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:867
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:11995
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1545
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1597
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:47
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:904
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:588
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12488
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:652
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:16944
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3548
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:12928
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11032
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10407
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1761
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:764
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:833
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:506
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5740
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1009
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12308
Under
@ Under
Definition: TrackUnit.h:77
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16468
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:721
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:696
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:548
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2805
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11183
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11503
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:871
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:356
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:137
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10305
Lead
@ Lead
Definition: TrackUnit.h:77
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5605
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1795
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13176
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:787
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:554
TTrack::WriteTrackToImage
void WriteTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3764
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5421
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6199
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:87
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1242
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9029
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:579
TTrack::Up
@ Up
Definition: TrackUnit.h:533
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:863
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:723
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:510
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10284
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:923
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1383
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8321
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1538
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:663
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:219
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17011
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1527
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:781
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6085
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:725
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:623
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8267
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:783
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7090
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9696
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:77
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:497
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:515
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:693
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17461
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:155
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1529
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12358
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:10928
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4524
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:495
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackElement.at(At)
Definition: TrackUnit.cpp:10257
TGraphicElement::Width
int Width
Definition: TrackUnit.h:363
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18368
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:18578
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17287
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:698
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:742
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:570
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:636
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TTrack::WriteOperatingTrackToImage
void WriteOperatingTrackToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track element graphics to the image file in...
Definition: TrackUnit.cpp:4065
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:771
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14006
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:580
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4043
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2340
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:613
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9169
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12126
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:589
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:862
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:860
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5581
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18661
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:568
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1425
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:910
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:769
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1414
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:828
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6788
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:667
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1029
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1031
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7565
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17103
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:581
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7163
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:785
Erase
@ Erase
Definition: TrackUnit.h:68
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:832
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5226
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:721
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1577
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:812
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:859
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:576
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:12998
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:540
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:10840
Parapet
@ Parapet
Definition: TrackUnit.h:68
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17130
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:786
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:993
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:285
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8838
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17076
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:852
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:721
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:17996
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:591
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:915
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:696
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:784
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:149
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:807
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1034
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:646
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:799
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:14441
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:824
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:139
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:221
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11060
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12053
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1192
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17039
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:597
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:732
TTrack
Definition: TrackUnit.h:473
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1250
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:768
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1281
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18145
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1514
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7866
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:621
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:513
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:841
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:651
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:727
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:850
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:130
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:806
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:686
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:219
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:17636
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:227
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2885
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8682
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:909
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:5979
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2092
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:512
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:725
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:160
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:845
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:704
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2558
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:217
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1512
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7529
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:11841
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12619
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:511
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1389
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10194
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8230
IDInt
Definition: TrackUnit.h:422
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2321
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:574
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:18629
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:598
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:779
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4328
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:9944
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:4971
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:147
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:808
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:773
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:822
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:365
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:18726
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1106
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:8952
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:495
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:99
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7476
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1193
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:155
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:886
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:682
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:731
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:632
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:225
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:848
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:13802
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1582
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:132
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:768
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7444
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:554
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:809
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:782
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:716
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:149
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:803
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:755
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1400
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:839
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1518
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:836
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1528
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4596
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:571
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:8778
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:655
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:14989
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1220
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:717
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:359
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13104
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:813
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1199
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:153
Points
@ Points
Definition: TrackUnit.h:67
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:703
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:724
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:17709
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:854
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9627
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:10911
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:583
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:821
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
Trail
@ Trail
Definition: TrackUnit.h:77
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:16988
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9011
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:16587
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:762
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1831
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:805
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16405
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:818
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:648
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:726
Continuation
@ Continuation
Definition: TrackUnit.h:67
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1025
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7323
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:47
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3648
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5817
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:515
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9058
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:853
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:861
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:869
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:11884
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:501
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:823
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:753
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:858
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:359
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14450
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:515
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1014
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3265
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:363
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:874
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1417
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:689
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:622
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:648
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1576
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:911
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:279
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:729
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:837
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:18808
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:12823
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1003
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:767
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1391
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1007
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:688
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:616
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:797
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4581
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:872
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:17607
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1609
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8368
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:699
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:617
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:577
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:708
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:653
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10698
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:811
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:628
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1252
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18645
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:505
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1841
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4566
Connection
@ Connection
Definition: TrackUnit.h:77
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3625
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1584
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9290
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:994
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:733
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16218
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11702
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:707
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:810
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8294
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:860
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1012
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:17918
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:17874
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6861
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:541
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10569
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:692
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:851
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:642
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1279
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:883
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5625
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:844
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:708
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:359
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:675
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9750
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:497
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:644
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:655
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17144
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4706
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:788
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2661
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:675
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7404
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3027
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:840
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:134
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:865
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16376
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:550
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13368
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:293
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:673
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:590
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:614
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:614
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1193
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:575
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:585
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:899
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:625
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11262
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:359
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:918
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:102
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1387
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:214
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8417
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:798
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1739
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8599
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:626
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:572
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:632
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13075
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:18613
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:143
TTrack::TBarrierState
TBarrierState
< state of barriers
Definition: TrackUnit.h:532
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1249
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4183
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:714
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4457
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1936
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1020
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6125
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:991
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:695
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:825
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:627
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7118
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1281
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:227
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:587
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:870
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:679
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:651
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4482
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:690
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1522
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1027
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:765
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:921
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7817
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:665
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1206
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:795
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:830
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9207
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1001
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:754
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:10805
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1746
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:815
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:624
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1389
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15410
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7306
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:716
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:151
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:780
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:678
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1391
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:537
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6142
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:709
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3525
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:757
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:643
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:508
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:787
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:661
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10731
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:774
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:866
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:834
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:151
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:601
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:912
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:279
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:694
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:546
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:713
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1054
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:567
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:15784
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:608
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:719
RouteCall
@ RouteCall
Definition: TrackUnit.h:1199
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11196
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:846
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:592
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:77
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:591
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18190
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:241
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:593
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:580
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10760
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10026
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:596
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:532
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:217
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:776
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:914
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6043
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:160
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:68
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:922
TRailGraphics::smTransparent
Graphics::TBitmap * smTransparent
Definition: GraphicUnit.h:888
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:653
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11208
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1254
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:145
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1511
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:838
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:722
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:808
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:693
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:497
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:615
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10017
Bridge
@ Bridge
Definition: TrackUnit.h:67
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:849
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1193
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:797
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:77
Buffers
@ Buffers
Definition: TrackUnit.h:67
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16134
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:690
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:77
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11220
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4394
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11143
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:833